]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/config/tc-arm.c
* gas/arm/iwmmxt.d: Add -miwmmxt to #objdump line, to get the
[thirdparty/binutils-gdb.git] / gas / config / tc-arm.c
CommitLineData
b99bd4ef 1/* tc-arm.c -- Assemble for the ARM
ae6063d4 2 Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
b99bd4ef
NC
3 Free Software Foundation, Inc.
4 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
5 Modified by David Taylor (dtaylor@armltd.co.uk)
22d9c8c5 6 Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
b99bd4ef
NC
7
8 This file is part of GAS, the GNU Assembler.
9
10 GAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 GAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GAS; see the file COPYING. If not, write to the Free
22 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 02111-1307, USA. */
24
b99bd4ef
NC
25#include <string.h>
26#define NO_RELOC 0
27#include "as.h"
3882b010 28#include "safe-ctype.h"
b99bd4ef
NC
29
30/* Need TARGET_CPU. */
31#include "config.h"
32#include "subsegs.h"
33#include "obstack.h"
34#include "symbols.h"
35#include "listing.h"
36
37#ifdef OBJ_ELF
38#include "elf/arm.h"
39#include "dwarf2dbg.h"
40#endif
41
03b1477f
RE
42/* XXX Set this to 1 after the next binutils release */
43#define WARN_DEPRECATED 0
44
b89dddec
RE
45/* The following bitmasks control CPU extensions: */
46#define ARM_EXT_V1 0x00000001 /* All processors (core set). */
47#define ARM_EXT_V2 0x00000002 /* Multiply instructions. */
48#define ARM_EXT_V2S 0x00000004 /* SWP instructions. */
49#define ARM_EXT_V3 0x00000008 /* MSR MRS. */
50#define ARM_EXT_V3M 0x00000010 /* Allow long multiplies. */
51#define ARM_EXT_V4 0x00000020 /* Allow half word loads. */
52#define ARM_EXT_V4T 0x00000040 /* Thumb v1. */
53#define ARM_EXT_V5 0x00000080 /* Allow CLZ, etc. */
54#define ARM_EXT_V5T 0x00000100 /* Thumb v2. */
55#define ARM_EXT_V5ExP 0x00000200 /* DSP core set. */
56#define ARM_EXT_V5E 0x00000400 /* DSP Double transfers. */
ea6ef066 57#define ARM_EXT_V5J 0x00000800 /* Jazelle extension. */
03b1477f
RE
58
59/* Co-processor space extensions. */
60#define ARM_CEXT_XSCALE 0x00800000 /* Allow MIA etc. */
61#define ARM_CEXT_MAVERICK 0x00400000 /* Use Cirrus/DSP coprocessor. */
5a6c6817 62#define ARM_CEXT_IWMMXT 0x00200000 /* Intel Wireless MMX technology coprocessor. */
b89dddec
RE
63
64/* Architectures are the sum of the base and extensions. The ARM ARM (rev E)
65 defines the following: ARMv3, ARMv3M, ARMv4xM, ARMv4, ARMv4TxM, ARMv4T,
66 ARMv5xM, ARMv5, ARMv5TxM, ARMv5T, ARMv5TExP, ARMv5TE. To these we add
67 three more to cover cores prior to ARM6. Finally, there are cores which
68 implement further extensions in the co-processor space. */
69#define ARM_ARCH_V1 ARM_EXT_V1
70#define ARM_ARCH_V2 (ARM_ARCH_V1 | ARM_EXT_V2)
71#define ARM_ARCH_V2S (ARM_ARCH_V2 | ARM_EXT_V2S)
72#define ARM_ARCH_V3 (ARM_ARCH_V2S | ARM_EXT_V3)
73#define ARM_ARCH_V3M (ARM_ARCH_V3 | ARM_EXT_V3M)
74#define ARM_ARCH_V4xM (ARM_ARCH_V3 | ARM_EXT_V4)
75#define ARM_ARCH_V4 (ARM_ARCH_V3M | ARM_EXT_V4)
76#define ARM_ARCH_V4TxM (ARM_ARCH_V4xM | ARM_EXT_V4T)
77#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_EXT_V4T)
78#define ARM_ARCH_V5xM (ARM_ARCH_V4xM | ARM_EXT_V5)
79#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5)
80#define ARM_ARCH_V5TxM (ARM_ARCH_V5xM | ARM_EXT_V4T | ARM_EXT_V5T)
81#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_EXT_V4T | ARM_EXT_V5T)
82#define ARM_ARCH_V5TExP (ARM_ARCH_V5T | ARM_EXT_V5ExP)
83#define ARM_ARCH_V5TE (ARM_ARCH_V5TExP | ARM_EXT_V5E)
ea6ef066 84#define ARM_ARCH_V5TEJ (ARM_ARCH_V5TE | ARM_EXT_V5J)
03b1477f 85
b89dddec 86/* Processors with specific extensions in the co-processor space. */
03b1477f 87#define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_CEXT_XSCALE)
5a6c6817 88#define ARM_ARCH_IWMMXT (ARM_ARCH_XSCALE | ARM_CEXT_IWMMXT)
b99bd4ef
NC
89
90/* Some useful combinations: */
03b1477f
RE
91#define ARM_ANY 0x0000ffff /* Any basic core. */
92#define ARM_ALL 0x00ffffff /* Any core + co-processor */
93#define CPROC_ANY 0x00ff0000 /* Any co-processor */
94#define FPU_ANY 0xff000000 /* Note this is ~ARM_ALL. */
95
b99bd4ef 96
bfae80f2
RE
97#define FPU_FPA_EXT_V1 0x80000000 /* Base FPA instruction set. */
98#define FPU_FPA_EXT_V2 0x40000000 /* LFM/SFM. */
99#define FPU_VFP_EXT_NONE 0x20000000 /* Use VFP word-ordering. */
100#define FPU_VFP_EXT_V1xD 0x10000000 /* Base VFP instruction set. */
101#define FPU_VFP_EXT_V1 0x08000000 /* Double-precision insns. */
102#define FPU_VFP_EXT_V2 0x04000000 /* ARM10E VFPr1. */
103#define FPU_NONE 0
b99bd4ef 104
b89dddec
RE
105#define FPU_ARCH_FPE FPU_FPA_EXT_V1
106#define FPU_ARCH_FPA (FPU_ARCH_FPE | FPU_FPA_EXT_V2)
107
bfae80f2
RE
108#define FPU_ARCH_VFP FPU_VFP_EXT_NONE
109#define FPU_ARCH_VFP_V1xD (FPU_VFP_EXT_V1xD | FPU_VFP_EXT_NONE)
110#define FPU_ARCH_VFP_V1 (FPU_ARCH_VFP_V1xD | FPU_VFP_EXT_V1)
111#define FPU_ARCH_VFP_V2 (FPU_ARCH_VFP_V1 | FPU_VFP_EXT_V2)
112
b89dddec
RE
113/* Types of processor to assemble for. */
114#define ARM_1 ARM_ARCH_V1
115#define ARM_2 ARM_ARCH_V2
116#define ARM_3 ARM_ARCH_V2S
117#define ARM_250 ARM_ARCH_V2S
118#define ARM_6 ARM_ARCH_V3
119#define ARM_7 ARM_ARCH_V3
120#define ARM_8 ARM_ARCH_V4
121#define ARM_9 ARM_ARCH_V4T
122#define ARM_STRONG ARM_ARCH_V4
123#define ARM_CPU_MASK 0x0000000f /* XXX? */
b99bd4ef
NC
124
125#ifndef CPU_DEFAULT
126#if defined __XSCALE__
b89dddec 127#define CPU_DEFAULT (ARM_ARCH_XSCALE)
b99bd4ef
NC
128#else
129#if defined __thumb__
b89dddec 130#define CPU_DEFAULT (ARM_ARCH_V5T)
b99bd4ef 131#else
03b1477f 132#define CPU_DEFAULT ARM_ANY
b99bd4ef
NC
133#endif
134#endif
135#endif
136
39c2da32
RE
137#ifdef TE_LINUX
138#define FPU_DEFAULT FPU_ARCH_FPA
139#endif
140
141#ifdef TE_NetBSD
142#ifdef OBJ_ELF
143#define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, but VFP order. */
144#else
145/* Legacy a.out format. */
146#define FPU_DEFAULT FPU_ARCH_FPA /* Soft-float, but FPA order. */
147#endif
148#endif
149
bfae80f2 150/* For backwards compatibility we default to the FPA. */
b99bd4ef 151#ifndef FPU_DEFAULT
b89dddec 152#define FPU_DEFAULT FPU_ARCH_FPA
b99bd4ef
NC
153#endif
154
155#define streq(a, b) (strcmp (a, b) == 0)
156#define skip_whitespace(str) while (*(str) == ' ') ++(str)
157
03b1477f 158static unsigned long cpu_variant;
b99bd4ef
NC
159static int target_oabi = 0;
160
b99bd4ef 161/* Flags stored in private area of BFD structure. */
b34976b6
AM
162static int uses_apcs_26 = FALSE;
163static int atpcs = FALSE;
164static int support_interwork = FALSE;
165static int uses_apcs_float = FALSE;
166static int pic_code = FALSE;
03b1477f
RE
167
168/* Variables that we set while parsing command-line options. Once all
169 options have been read we re-process these values to set the real
170 assembly flags. */
171static int legacy_cpu = -1;
172static int legacy_fpu = -1;
173
174static int mcpu_cpu_opt = -1;
175static int mcpu_fpu_opt = -1;
176static int march_cpu_opt = -1;
177static int march_fpu_opt = -1;
178static int mfpu_opt = -1;
b99bd4ef
NC
179
180/* This array holds the chars that always start a comment. If the
181 pre-processor is disabled, these aren't very useful. */
f57c81f6 182const char comment_chars[] = "@";
b99bd4ef
NC
183
184/* This array holds the chars that only start a comment at the beginning of
185 a line. If the line seems to have the form '# 123 filename'
186 .line and .file directives will appear in the pre-processed output. */
187/* Note that input_file.c hand checks for '#' at the beginning of the
188 first line of the input file. This is because the compiler outputs
189 #NO_APP at the beginning of its output. */
190/* Also note that comments like this one will always work. */
05d2d07e 191const char line_comment_chars[] = "#";
b99bd4ef 192
da89cce1 193const char line_separator_chars[] = ";";
b99bd4ef
NC
194
195/* Chars that can be used to separate mant
196 from exp in floating point numbers. */
05d2d07e 197const char EXP_CHARS[] = "eE";
b99bd4ef
NC
198
199/* Chars that mean this number is a floating point constant. */
200/* As in 0f12.456 */
201/* or 0d1.2345e12 */
202
05d2d07e 203const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
b99bd4ef
NC
204
205/* Prefix characters that indicate the start of an immediate
206 value. */
207#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
208
209#ifdef OBJ_ELF
210/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
211symbolS * GOT_symbol;
212#endif
213
214/* Size of relocation record. */
05d2d07e 215const int md_reloc_size = 8;
b99bd4ef
NC
216
217/* 0: assemble for ARM,
218 1: assemble for Thumb,
219 2: assemble for Thumb even though target CPU does not support thumb
220 instructions. */
221static int thumb_mode = 0;
222
223typedef struct arm_fix
224{
225 int thumb_mode;
226} arm_fix_data;
227
228struct arm_it
229{
05d2d07e 230 const char * error;
b99bd4ef 231 unsigned long instruction;
b99bd4ef
NC
232 int size;
233 struct
234 {
235 bfd_reloc_code_real_type type;
236 expressionS exp;
237 int pc_rel;
238 } reloc;
239};
240
241struct arm_it inst;
242
243enum asm_shift_index
244{
245 SHIFT_LSL = 0,
246 SHIFT_LSR,
247 SHIFT_ASR,
248 SHIFT_ROR,
249 SHIFT_RRX
250};
251
252struct asm_shift_properties
253{
254 enum asm_shift_index index;
255 unsigned long bit_field;
256 unsigned int allows_0 : 1;
257 unsigned int allows_32 : 1;
258};
259
260static const struct asm_shift_properties shift_properties [] =
261{
262 { SHIFT_LSL, 0, 1, 0},
263 { SHIFT_LSR, 0x20, 0, 1},
264 { SHIFT_ASR, 0x40, 0, 1},
265 { SHIFT_ROR, 0x60, 0, 0},
266 { SHIFT_RRX, 0x60, 0, 0}
267};
268
269struct asm_shift_name
270{
271 const char * name;
272 const struct asm_shift_properties * properties;
273};
274
275static const struct asm_shift_name shift_names [] =
276{
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 { "ASL", shift_properties + SHIFT_LSL },
284 { "LSL", shift_properties + SHIFT_LSL },
285 { "LSR", shift_properties + SHIFT_LSR },
286 { "ASR", shift_properties + SHIFT_ASR },
287 { "ROR", shift_properties + SHIFT_ROR },
288 { "RRX", shift_properties + SHIFT_RRX }
289};
290
291#define NO_SHIFT_RESTRICT 1
292#define SHIFT_RESTRICT 0
293
294#define NUM_FLOAT_VALS 8
295
05d2d07e 296const char * fp_const[] =
b99bd4ef
NC
297{
298 "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
299};
300
301/* Number of littlenums required to hold an extended precision number. */
302#define MAX_LITTLENUMS 6
303
304LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
305
306#define FAIL (-1)
307#define SUCCESS (0)
308
bfae80f2
RE
309/* Whether a Co-processor load/store operation accepts write-back forms. */
310#define CP_WB_OK 1
311#define CP_NO_WB 0
312
b99bd4ef
NC
313#define SUFF_S 1
314#define SUFF_D 2
315#define SUFF_E 3
316#define SUFF_P 4
317
318#define CP_T_X 0x00008000
319#define CP_T_Y 0x00400000
320#define CP_T_Pre 0x01000000
321#define CP_T_UD 0x00800000
322#define CP_T_WB 0x00200000
323
324#define CONDS_BIT 0x00100000
325#define LOAD_BIT 0x00100000
b99bd4ef
NC
326
327#define DOUBLE_LOAD_FLAG 0x00000001
328
329struct asm_cond
330{
05d2d07e 331 const char * template;
b99bd4ef
NC
332 unsigned long value;
333};
334
b99bd4ef 335#define COND_ALWAYS 0xe0000000
90e4755a 336#define COND_MASK 0xf0000000
b99bd4ef 337
05d2d07e 338static const struct asm_cond conds[] =
b99bd4ef
NC
339{
340 {"eq", 0x00000000},
341 {"ne", 0x10000000},
342 {"cs", 0x20000000}, {"hs", 0x20000000},
343 {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000},
344 {"mi", 0x40000000},
345 {"pl", 0x50000000},
346 {"vs", 0x60000000},
347 {"vc", 0x70000000},
348 {"hi", 0x80000000},
349 {"ls", 0x90000000},
350 {"ge", 0xa0000000},
351 {"lt", 0xb0000000},
352 {"gt", 0xc0000000},
353 {"le", 0xd0000000},
354 {"al", 0xe0000000},
355 {"nv", 0xf0000000}
356};
357
b99bd4ef
NC
358struct asm_psr
359{
b34976b6
AM
360 const char *template;
361 bfd_boolean cpsr;
b99bd4ef
NC
362 unsigned long field;
363};
364
365/* The bit that distnguishes CPSR and SPSR. */
366#define SPSR_BIT (1 << 22)
367
368/* How many bits to shift the PSR_xxx bits up by. */
369#define PSR_SHIFT 16
370
371#define PSR_c (1 << 0)
372#define PSR_x (1 << 1)
373#define PSR_s (1 << 2)
374#define PSR_f (1 << 3)
375
05d2d07e 376static const struct asm_psr psrs[] =
b99bd4ef 377{
b34976b6
AM
378 {"CPSR", TRUE, PSR_c | PSR_f},
379 {"CPSR_all", TRUE, PSR_c | PSR_f},
380 {"SPSR", FALSE, PSR_c | PSR_f},
381 {"SPSR_all", FALSE, PSR_c | PSR_f},
382 {"CPSR_flg", TRUE, PSR_f},
383 {"CPSR_f", TRUE, PSR_f},
384 {"SPSR_flg", FALSE, PSR_f},
385 {"SPSR_f", FALSE, PSR_f},
386 {"CPSR_c", TRUE, PSR_c},
387 {"CPSR_ctl", TRUE, PSR_c},
388 {"SPSR_c", FALSE, PSR_c},
389 {"SPSR_ctl", FALSE, PSR_c},
390 {"CPSR_x", TRUE, PSR_x},
391 {"CPSR_s", TRUE, PSR_s},
392 {"SPSR_x", FALSE, PSR_x},
393 {"SPSR_s", FALSE, PSR_s},
b99bd4ef 394 /* Combinations of flags. */
b34976b6
AM
395 {"CPSR_fs", TRUE, PSR_f | PSR_s},
396 {"CPSR_fx", TRUE, PSR_f | PSR_x},
397 {"CPSR_fc", TRUE, PSR_f | PSR_c},
398 {"CPSR_sf", TRUE, PSR_s | PSR_f},
399 {"CPSR_sx", TRUE, PSR_s | PSR_x},
400 {"CPSR_sc", TRUE, PSR_s | PSR_c},
401 {"CPSR_xf", TRUE, PSR_x | PSR_f},
402 {"CPSR_xs", TRUE, PSR_x | PSR_s},
403 {"CPSR_xc", TRUE, PSR_x | PSR_c},
404 {"CPSR_cf", TRUE, PSR_c | PSR_f},
405 {"CPSR_cs", TRUE, PSR_c | PSR_s},
406 {"CPSR_cx", TRUE, PSR_c | PSR_x},
407 {"CPSR_fsx", TRUE, PSR_f | PSR_s | PSR_x},
408 {"CPSR_fsc", TRUE, PSR_f | PSR_s | PSR_c},
409 {"CPSR_fxs", TRUE, PSR_f | PSR_x | PSR_s},
410 {"CPSR_fxc", TRUE, PSR_f | PSR_x | PSR_c},
411 {"CPSR_fcs", TRUE, PSR_f | PSR_c | PSR_s},
412 {"CPSR_fcx", TRUE, PSR_f | PSR_c | PSR_x},
413 {"CPSR_sfx", TRUE, PSR_s | PSR_f | PSR_x},
414 {"CPSR_sfc", TRUE, PSR_s | PSR_f | PSR_c},
415 {"CPSR_sxf", TRUE, PSR_s | PSR_x | PSR_f},
416 {"CPSR_sxc", TRUE, PSR_s | PSR_x | PSR_c},
417 {"CPSR_scf", TRUE, PSR_s | PSR_c | PSR_f},
418 {"CPSR_scx", TRUE, PSR_s | PSR_c | PSR_x},
419 {"CPSR_xfs", TRUE, PSR_x | PSR_f | PSR_s},
420 {"CPSR_xfc", TRUE, PSR_x | PSR_f | PSR_c},
421 {"CPSR_xsf", TRUE, PSR_x | PSR_s | PSR_f},
422 {"CPSR_xsc", TRUE, PSR_x | PSR_s | PSR_c},
423 {"CPSR_xcf", TRUE, PSR_x | PSR_c | PSR_f},
424 {"CPSR_xcs", TRUE, PSR_x | PSR_c | PSR_s},
425 {"CPSR_cfs", TRUE, PSR_c | PSR_f | PSR_s},
426 {"CPSR_cfx", TRUE, PSR_c | PSR_f | PSR_x},
427 {"CPSR_csf", TRUE, PSR_c | PSR_s | PSR_f},
428 {"CPSR_csx", TRUE, PSR_c | PSR_s | PSR_x},
429 {"CPSR_cxf", TRUE, PSR_c | PSR_x | PSR_f},
430 {"CPSR_cxs", TRUE, PSR_c | PSR_x | PSR_s},
431 {"CPSR_fsxc", TRUE, PSR_f | PSR_s | PSR_x | PSR_c},
432 {"CPSR_fscx", TRUE, PSR_f | PSR_s | PSR_c | PSR_x},
433 {"CPSR_fxsc", TRUE, PSR_f | PSR_x | PSR_s | PSR_c},
434 {"CPSR_fxcs", TRUE, PSR_f | PSR_x | PSR_c | PSR_s},
435 {"CPSR_fcsx", TRUE, PSR_f | PSR_c | PSR_s | PSR_x},
436 {"CPSR_fcxs", TRUE, PSR_f | PSR_c | PSR_x | PSR_s},
437 {"CPSR_sfxc", TRUE, PSR_s | PSR_f | PSR_x | PSR_c},
438 {"CPSR_sfcx", TRUE, PSR_s | PSR_f | PSR_c | PSR_x},
439 {"CPSR_sxfc", TRUE, PSR_s | PSR_x | PSR_f | PSR_c},
440 {"CPSR_sxcf", TRUE, PSR_s | PSR_x | PSR_c | PSR_f},
441 {"CPSR_scfx", TRUE, PSR_s | PSR_c | PSR_f | PSR_x},
442 {"CPSR_scxf", TRUE, PSR_s | PSR_c | PSR_x | PSR_f},
443 {"CPSR_xfsc", TRUE, PSR_x | PSR_f | PSR_s | PSR_c},
444 {"CPSR_xfcs", TRUE, PSR_x | PSR_f | PSR_c | PSR_s},
445 {"CPSR_xsfc", TRUE, PSR_x | PSR_s | PSR_f | PSR_c},
446 {"CPSR_xscf", TRUE, PSR_x | PSR_s | PSR_c | PSR_f},
447 {"CPSR_xcfs", TRUE, PSR_x | PSR_c | PSR_f | PSR_s},
448 {"CPSR_xcsf", TRUE, PSR_x | PSR_c | PSR_s | PSR_f},
449 {"CPSR_cfsx", TRUE, PSR_c | PSR_f | PSR_s | PSR_x},
450 {"CPSR_cfxs", TRUE, PSR_c | PSR_f | PSR_x | PSR_s},
451 {"CPSR_csfx", TRUE, PSR_c | PSR_s | PSR_f | PSR_x},
452 {"CPSR_csxf", TRUE, PSR_c | PSR_s | PSR_x | PSR_f},
453 {"CPSR_cxfs", TRUE, PSR_c | PSR_x | PSR_f | PSR_s},
454 {"CPSR_cxsf", TRUE, PSR_c | PSR_x | PSR_s | PSR_f},
455 {"SPSR_fs", FALSE, PSR_f | PSR_s},
456 {"SPSR_fx", FALSE, PSR_f | PSR_x},
457 {"SPSR_fc", FALSE, PSR_f | PSR_c},
458 {"SPSR_sf", FALSE, PSR_s | PSR_f},
459 {"SPSR_sx", FALSE, PSR_s | PSR_x},
460 {"SPSR_sc", FALSE, PSR_s | PSR_c},
461 {"SPSR_xf", FALSE, PSR_x | PSR_f},
462 {"SPSR_xs", FALSE, PSR_x | PSR_s},
463 {"SPSR_xc", FALSE, PSR_x | PSR_c},
464 {"SPSR_cf", FALSE, PSR_c | PSR_f},
465 {"SPSR_cs", FALSE, PSR_c | PSR_s},
466 {"SPSR_cx", FALSE, PSR_c | PSR_x},
467 {"SPSR_fsx", FALSE, PSR_f | PSR_s | PSR_x},
468 {"SPSR_fsc", FALSE, PSR_f | PSR_s | PSR_c},
469 {"SPSR_fxs", FALSE, PSR_f | PSR_x | PSR_s},
470 {"SPSR_fxc", FALSE, PSR_f | PSR_x | PSR_c},
471 {"SPSR_fcs", FALSE, PSR_f | PSR_c | PSR_s},
472 {"SPSR_fcx", FALSE, PSR_f | PSR_c | PSR_x},
473 {"SPSR_sfx", FALSE, PSR_s | PSR_f | PSR_x},
474 {"SPSR_sfc", FALSE, PSR_s | PSR_f | PSR_c},
475 {"SPSR_sxf", FALSE, PSR_s | PSR_x | PSR_f},
476 {"SPSR_sxc", FALSE, PSR_s | PSR_x | PSR_c},
477 {"SPSR_scf", FALSE, PSR_s | PSR_c | PSR_f},
478 {"SPSR_scx", FALSE, PSR_s | PSR_c | PSR_x},
479 {"SPSR_xfs", FALSE, PSR_x | PSR_f | PSR_s},
480 {"SPSR_xfc", FALSE, PSR_x | PSR_f | PSR_c},
481 {"SPSR_xsf", FALSE, PSR_x | PSR_s | PSR_f},
482 {"SPSR_xsc", FALSE, PSR_x | PSR_s | PSR_c},
483 {"SPSR_xcf", FALSE, PSR_x | PSR_c | PSR_f},
484 {"SPSR_xcs", FALSE, PSR_x | PSR_c | PSR_s},
485 {"SPSR_cfs", FALSE, PSR_c | PSR_f | PSR_s},
486 {"SPSR_cfx", FALSE, PSR_c | PSR_f | PSR_x},
487 {"SPSR_csf", FALSE, PSR_c | PSR_s | PSR_f},
488 {"SPSR_csx", FALSE, PSR_c | PSR_s | PSR_x},
489 {"SPSR_cxf", FALSE, PSR_c | PSR_x | PSR_f},
490 {"SPSR_cxs", FALSE, PSR_c | PSR_x | PSR_s},
491 {"SPSR_fsxc", FALSE, PSR_f | PSR_s | PSR_x | PSR_c},
492 {"SPSR_fscx", FALSE, PSR_f | PSR_s | PSR_c | PSR_x},
493 {"SPSR_fxsc", FALSE, PSR_f | PSR_x | PSR_s | PSR_c},
494 {"SPSR_fxcs", FALSE, PSR_f | PSR_x | PSR_c | PSR_s},
495 {"SPSR_fcsx", FALSE, PSR_f | PSR_c | PSR_s | PSR_x},
496 {"SPSR_fcxs", FALSE, PSR_f | PSR_c | PSR_x | PSR_s},
497 {"SPSR_sfxc", FALSE, PSR_s | PSR_f | PSR_x | PSR_c},
498 {"SPSR_sfcx", FALSE, PSR_s | PSR_f | PSR_c | PSR_x},
499 {"SPSR_sxfc", FALSE, PSR_s | PSR_x | PSR_f | PSR_c},
500 {"SPSR_sxcf", FALSE, PSR_s | PSR_x | PSR_c | PSR_f},
501 {"SPSR_scfx", FALSE, PSR_s | PSR_c | PSR_f | PSR_x},
502 {"SPSR_scxf", FALSE, PSR_s | PSR_c | PSR_x | PSR_f},
503 {"SPSR_xfsc", FALSE, PSR_x | PSR_f | PSR_s | PSR_c},
504 {"SPSR_xfcs", FALSE, PSR_x | PSR_f | PSR_c | PSR_s},
505 {"SPSR_xsfc", FALSE, PSR_x | PSR_s | PSR_f | PSR_c},
506 {"SPSR_xscf", FALSE, PSR_x | PSR_s | PSR_c | PSR_f},
507 {"SPSR_xcfs", FALSE, PSR_x | PSR_c | PSR_f | PSR_s},
508 {"SPSR_xcsf", FALSE, PSR_x | PSR_c | PSR_s | PSR_f},
509 {"SPSR_cfsx", FALSE, PSR_c | PSR_f | PSR_s | PSR_x},
510 {"SPSR_cfxs", FALSE, PSR_c | PSR_f | PSR_x | PSR_s},
511 {"SPSR_csfx", FALSE, PSR_c | PSR_s | PSR_f | PSR_x},
512 {"SPSR_csxf", FALSE, PSR_c | PSR_s | PSR_x | PSR_f},
513 {"SPSR_cxfs", FALSE, PSR_c | PSR_x | PSR_f | PSR_s},
514 {"SPSR_cxsf", FALSE, PSR_c | PSR_x | PSR_s | PSR_f},
b99bd4ef
NC
515};
516
e16bb312
NC
517enum wreg_type
518 {
519 IWMMXT_REG_WR = 0,
520 IWMMXT_REG_WC = 1,
521 IWMMXT_REG_WR_OR_WC = 2,
522 IWMMXT_REG_WCG
523 };
524
525enum iwmmxt_insn_type
526{
527 check_rd,
528 check_wr,
529 check_wrwr,
530 check_wrwrwr,
531 check_wrwrwcg,
532 check_tbcst,
533 check_tmovmsk,
534 check_tmia,
535 check_tmcrr,
536 check_tmrrc,
537 check_tmcr,
538 check_tmrc,
539 check_tinsr,
540 check_textrc,
541 check_waligni,
542 check_textrm,
543 check_wshufh
544};
545
bfae80f2
RE
546enum vfp_dp_reg_pos
547{
548 VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
549};
550
551enum vfp_sp_reg_pos
552{
553 VFP_REG_Sd, VFP_REG_Sm, VFP_REG_Sn
554};
555
556enum vfp_ldstm_type
557{
558 VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX
559};
560
561/* VFP system registers. */
562struct vfp_reg
563{
564 const char *name;
565 unsigned long regno;
566};
567
cc8a6dd0 568static const struct vfp_reg vfp_regs[] =
bfae80f2
RE
569{
570 {"fpsid", 0x00000000},
571 {"FPSID", 0x00000000},
572 {"fpscr", 0x00010000},
573 {"FPSCR", 0x00010000},
574 {"fpexc", 0x00080000},
575 {"FPEXC", 0x00080000}
576};
577
6c43fab6
RE
578/* Structure for a hash table entry for a register. */
579struct reg_entry
580{
581 const char * name;
582 int number;
583};
584
e28cd48c 585/* Some well known registers that we refer to directly elsewhere. */
6c43fab6
RE
586#define REG_SP 13
587#define REG_LR 14
588#define REG_PC 15
589
e16bb312
NC
590#define wr_register(reg) ((reg ^ WR_PREFIX) >= 0 && (reg ^ WR_PREFIX) <= 15)
591#define wc_register(reg) ((reg ^ WC_PREFIX) >= 0 && (reg ^ WC_PREFIX) <= 15)
592#define wcg_register(reg) ((reg ^ WC_PREFIX) >= 8 && (reg ^ WC_PREFIX) <= 11)
593
6c43fab6
RE
594/* These are the standard names. Users can add aliases with .req. */
595/* Integer Register Numbers. */
596static const struct reg_entry rn_table[] =
597{
598 {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
599 {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
600 {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
601 {"r12", 12}, {"r13", REG_SP}, {"r14", REG_LR}, {"r15", REG_PC},
602 /* ATPCS Synonyms. */
603 {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3},
604 {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7},
605 {"v5", 8}, {"v6", 9}, {"v7", 10}, {"v8", 11},
606 /* Well-known aliases. */
607 {"wr", 7},
608 {"sb", 9}, {"sl", 10}, {"fp", 11},
609 {"ip", 12}, {"sp", REG_SP}, {"lr", REG_LR}, {"pc", REG_PC},
610 {NULL, 0}
611};
612
e16bb312
NC
613#define WR_PREFIX 0x200
614#define WC_PREFIX 0x400
615
616static const struct reg_entry iwmmxt_table[] =
617{
5a6c6817 618 /* Intel Wireless MMX technology register names. */
e16bb312
NC
619 { "wr0", 0x0 | WR_PREFIX}, {"wr1", 0x1 | WR_PREFIX},
620 { "wr2", 0x2 | WR_PREFIX}, {"wr3", 0x3 | WR_PREFIX},
621 { "wr4", 0x4 | WR_PREFIX}, {"wr5", 0x5 | WR_PREFIX},
622 { "wr6", 0x6 | WR_PREFIX}, {"wr7", 0x7 | WR_PREFIX},
623 { "wr8", 0x8 | WR_PREFIX}, {"wr9", 0x9 | WR_PREFIX},
624 { "wr10", 0xa | WR_PREFIX}, {"wr11", 0xb | WR_PREFIX},
625 { "wr12", 0xc | WR_PREFIX}, {"wr13", 0xd | WR_PREFIX},
626 { "wr14", 0xe | WR_PREFIX}, {"wr15", 0xf | WR_PREFIX},
627 { "wcid", 0x0 | WC_PREFIX}, {"wcon", 0x1 | WC_PREFIX},
628 {"wcssf", 0x2 | WC_PREFIX}, {"wcasf", 0x3 | WC_PREFIX},
629 {"wcgr0", 0x8 | WC_PREFIX}, {"wcgr1", 0x9 | WC_PREFIX},
630 {"wcgr2", 0xa | WC_PREFIX}, {"wcgr3", 0xb | WC_PREFIX},
631
632 { "wR0", 0x0 | WR_PREFIX}, {"wR1", 0x1 | WR_PREFIX},
633 { "wR2", 0x2 | WR_PREFIX}, {"wR3", 0x3 | WR_PREFIX},
634 { "wR4", 0x4 | WR_PREFIX}, {"wR5", 0x5 | WR_PREFIX},
635 { "wR6", 0x6 | WR_PREFIX}, {"wR7", 0x7 | WR_PREFIX},
636 { "wR8", 0x8 | WR_PREFIX}, {"wR9", 0x9 | WR_PREFIX},
637 { "wR10", 0xa | WR_PREFIX}, {"wR11", 0xb | WR_PREFIX},
638 { "wR12", 0xc | WR_PREFIX}, {"wR13", 0xd | WR_PREFIX},
639 { "wR14", 0xe | WR_PREFIX}, {"wR15", 0xf | WR_PREFIX},
640 { "wCID", 0x0 | WC_PREFIX}, {"wCon", 0x1 | WC_PREFIX},
641 {"wCSSF", 0x2 | WC_PREFIX}, {"wCASF", 0x3 | WC_PREFIX},
642 {"wCGR0", 0x8 | WC_PREFIX}, {"wCGR1", 0x9 | WC_PREFIX},
643 {"wCGR2", 0xa | WC_PREFIX}, {"wCGR3", 0xb | WC_PREFIX},
644 {NULL, 0}
645};
646
6c43fab6
RE
647/* Co-processor Numbers. */
648static const struct reg_entry cp_table[] =
649{
650 {"p0", 0}, {"p1", 1}, {"p2", 2}, {"p3", 3},
651 {"p4", 4}, {"p5", 5}, {"p6", 6}, {"p7", 7},
652 {"p8", 8}, {"p9", 9}, {"p10", 10}, {"p11", 11},
653 {"p12", 12}, {"p13", 13}, {"p14", 14}, {"p15", 15},
654 {NULL, 0}
655};
656
657/* Co-processor Register Numbers. */
658static const struct reg_entry cn_table[] =
659{
660 {"c0", 0}, {"c1", 1}, {"c2", 2}, {"c3", 3},
661 {"c4", 4}, {"c5", 5}, {"c6", 6}, {"c7", 7},
662 {"c8", 8}, {"c9", 9}, {"c10", 10}, {"c11", 11},
663 {"c12", 12}, {"c13", 13}, {"c14", 14}, {"c15", 15},
664 /* Not really valid, but kept for back-wards compatibility. */
665 {"cr0", 0}, {"cr1", 1}, {"cr2", 2}, {"cr3", 3},
666 {"cr4", 4}, {"cr5", 5}, {"cr6", 6}, {"cr7", 7},
667 {"cr8", 8}, {"cr9", 9}, {"cr10", 10}, {"cr11", 11},
668 {"cr12", 12}, {"cr13", 13}, {"cr14", 14}, {"cr15", 15},
669 {NULL, 0}
670};
671
672/* FPA Registers. */
673static const struct reg_entry fn_table[] =
674{
675 {"f0", 0}, {"f1", 1}, {"f2", 2}, {"f3", 3},
676 {"f4", 4}, {"f5", 5}, {"f6", 6}, {"f7", 7},
677 {NULL, 0}
678};
679
bfae80f2
RE
680/* VFP SP Registers. */
681static const struct reg_entry sn_table[] =
682{
683 {"s0", 0}, {"s1", 1}, {"s2", 2}, {"s3", 3},
684 {"s4", 4}, {"s5", 5}, {"s6", 6}, {"s7", 7},
685 {"s8", 8}, {"s9", 9}, {"s10", 10}, {"s11", 11},
686 {"s12", 12}, {"s13", 13}, {"s14", 14}, {"s15", 15},
687 {"s16", 16}, {"s17", 17}, {"s18", 18}, {"s19", 19},
688 {"s20", 20}, {"s21", 21}, {"s22", 22}, {"s23", 23},
689 {"s24", 24}, {"s25", 25}, {"s26", 26}, {"s27", 27},
690 {"s28", 28}, {"s29", 29}, {"s30", 30}, {"s31", 31},
691 {NULL, 0}
692};
693
694/* VFP DP Registers. */
695static const struct reg_entry dn_table[] =
696{
697 {"d0", 0}, {"d1", 1}, {"d2", 2}, {"d3", 3},
698 {"d4", 4}, {"d5", 5}, {"d6", 6}, {"d7", 7},
699 {"d8", 8}, {"d9", 9}, {"d10", 10}, {"d11", 11},
700 {"d12", 12}, {"d13", 13}, {"d14", 14}, {"d15", 15},
701 {NULL, 0}
702};
703
63e63b07 704/* Maverick DSP coprocessor registers. */
6c43fab6
RE
705static const struct reg_entry mav_mvf_table[] =
706{
707 {"mvf0", 0}, {"mvf1", 1}, {"mvf2", 2}, {"mvf3", 3},
708 {"mvf4", 4}, {"mvf5", 5}, {"mvf6", 6}, {"mvf7", 7},
709 {"mvf8", 8}, {"mvf9", 9}, {"mvf10", 10}, {"mvf11", 11},
710 {"mvf12", 12}, {"mvf13", 13}, {"mvf14", 14}, {"mvf15", 15},
711 {NULL, 0}
712};
713
714static const struct reg_entry mav_mvd_table[] =
715{
716 {"mvd0", 0}, {"mvd1", 1}, {"mvd2", 2}, {"mvd3", 3},
717 {"mvd4", 4}, {"mvd5", 5}, {"mvd6", 6}, {"mvd7", 7},
718 {"mvd8", 8}, {"mvd9", 9}, {"mvd10", 10}, {"mvd11", 11},
719 {"mvd12", 12}, {"mvd13", 13}, {"mvd14", 14}, {"mvd15", 15},
720 {NULL, 0}
721};
722
723static const struct reg_entry mav_mvfx_table[] =
724{
725 {"mvfx0", 0}, {"mvfx1", 1}, {"mvfx2", 2}, {"mvfx3", 3},
726 {"mvfx4", 4}, {"mvfx5", 5}, {"mvfx6", 6}, {"mvfx7", 7},
727 {"mvfx8", 8}, {"mvfx9", 9}, {"mvfx10", 10}, {"mvfx11", 11},
728 {"mvfx12", 12}, {"mvfx13", 13}, {"mvfx14", 14}, {"mvfx15", 15},
729 {NULL, 0}
730};
731
732static const struct reg_entry mav_mvdx_table[] =
733{
734 {"mvdx0", 0}, {"mvdx1", 1}, {"mvdx2", 2}, {"mvdx3", 3},
735 {"mvdx4", 4}, {"mvdx5", 5}, {"mvdx6", 6}, {"mvdx7", 7},
736 {"mvdx8", 8}, {"mvdx9", 9}, {"mvdx10", 10}, {"mvdx11", 11},
737 {"mvdx12", 12}, {"mvdx13", 13}, {"mvdx14", 14}, {"mvdx15", 15},
738 {NULL, 0}
739};
740
741static const struct reg_entry mav_mvax_table[] =
742{
743 {"mvax0", 0}, {"mvax1", 1}, {"mvax2", 2}, {"mvax3", 3},
744 {NULL, 0}
745};
746
747static const struct reg_entry mav_dspsc_table[] =
748{
749 {"dspsc", 0},
750 {NULL, 0}
751};
752
753struct reg_map
754{
755 const struct reg_entry *names;
756 int max_regno;
757 struct hash_control *htab;
758 const char *expected;
759};
760
761struct reg_map all_reg_maps[] =
762{
763 {rn_table, 15, NULL, N_("ARM register expected")},
f03698e6
RE
764 {cp_table, 15, NULL, N_("bad or missing co-processor number")},
765 {cn_table, 15, NULL, N_("co-processor register expected")},
6c43fab6 766 {fn_table, 7, NULL, N_("FPA register expected")},
bfae80f2
RE
767 {sn_table, 31, NULL, N_("VFP single precision register expected")},
768 {dn_table, 15, NULL, N_("VFP double precision register expected")},
6c43fab6
RE
769 {mav_mvf_table, 15, NULL, N_("Maverick MVF register expected")},
770 {mav_mvd_table, 15, NULL, N_("Maverick MVD register expected")},
771 {mav_mvfx_table, 15, NULL, N_("Maverick MVFX register expected")},
772 {mav_mvdx_table, 15, NULL, N_("Maverick MVFX register expected")},
773 {mav_mvax_table, 3, NULL, N_("Maverick MVAX register expected")},
774 {mav_dspsc_table, 0, NULL, N_("Maverick DSPSC register expected")},
5a6c6817 775 {iwmmxt_table, 23, NULL, N_("Intel Wireless MMX technology register expected")},
6c43fab6
RE
776};
777
778/* Enumeration matching entries in table above. */
779enum arm_reg_type
780{
781 REG_TYPE_RN = 0,
782#define REG_TYPE_FIRST REG_TYPE_RN
783 REG_TYPE_CP = 1,
784 REG_TYPE_CN = 2,
785 REG_TYPE_FN = 3,
bfae80f2
RE
786 REG_TYPE_SN = 4,
787 REG_TYPE_DN = 5,
788 REG_TYPE_MVF = 6,
789 REG_TYPE_MVD = 7,
790 REG_TYPE_MVFX = 8,
791 REG_TYPE_MVDX = 9,
792 REG_TYPE_MVAX = 10,
793 REG_TYPE_DSPSC = 11,
e16bb312 794 REG_TYPE_IWMMXT = 12,
bfae80f2 795
e16bb312 796 REG_TYPE_MAX = 13
6c43fab6 797};
404ff6b5 798
b99bd4ef
NC
799/* Functions called by parser. */
800/* ARM instructions. */
f2b7cb0a
RE
801static void do_arit PARAMS ((char *));
802static void do_cmp PARAMS ((char *));
803static void do_mov PARAMS ((char *));
804static void do_ldst PARAMS ((char *));
805static void do_ldstt PARAMS ((char *));
806static void do_ldmstm PARAMS ((char *));
807static void do_branch PARAMS ((char *));
808static void do_swi PARAMS ((char *));
c9b604bd 809
b99bd4ef 810/* Pseudo Op codes. */
f2b7cb0a
RE
811static void do_adr PARAMS ((char *));
812static void do_adrl PARAMS ((char *));
813static void do_empty PARAMS ((char *));
c9b604bd
RE
814
815/* ARM v2. */
f2b7cb0a
RE
816static void do_mul PARAMS ((char *));
817static void do_mla PARAMS ((char *));
c9b604bd
RE
818
819/* ARM v2S. */
f2b7cb0a 820static void do_swap PARAMS ((char *));
c9b604bd
RE
821
822/* ARM v3. */
f2b7cb0a
RE
823static void do_msr PARAMS ((char *));
824static void do_mrs PARAMS ((char *));
c9b604bd
RE
825
826/* ARM v3M. */
f2b7cb0a 827static void do_mull PARAMS ((char *));
b99bd4ef 828
90e4755a 829/* ARM v4. */
f2b7cb0a 830static void do_ldstv4 PARAMS ((char *));
90e4755a 831
c9b604bd 832/* ARM v4T. */
f2b7cb0a 833static void do_bx PARAMS ((char *));
b99bd4ef 834
ea6ef066 835/* ARM v5T. */
f2b7cb0a
RE
836static void do_blx PARAMS ((char *));
837static void do_bkpt PARAMS ((char *));
838static void do_clz PARAMS ((char *));
839static void do_lstc2 PARAMS ((char *));
840static void do_cdp2 PARAMS ((char *));
841static void do_co_reg2 PARAMS ((char *));
b99bd4ef 842
ea6ef066 843/* ARM v5TExP. */
f2b7cb0a
RE
844static void do_smla PARAMS ((char *));
845static void do_smlal PARAMS ((char *));
846static void do_smul PARAMS ((char *));
847static void do_qadd PARAMS ((char *));
c9b604bd 848
ea6ef066 849/* ARM v5TE. */
f2b7cb0a
RE
850static void do_pld PARAMS ((char *));
851static void do_ldrd PARAMS ((char *));
852static void do_co_reg2c PARAMS ((char *));
b99bd4ef 853
ea6ef066
RE
854/* ARM v5TEJ. */
855static void do_bxj PARAMS ((char *));
856
b99bd4ef 857/* Coprocessor Instructions. */
f2b7cb0a
RE
858static void do_cdp PARAMS ((char *));
859static void do_lstc PARAMS ((char *));
860static void do_co_reg PARAMS ((char *));
c9b604bd
RE
861
862/* FPA instructions. */
f2b7cb0a
RE
863static void do_fpa_ctrl PARAMS ((char *));
864static void do_fpa_ldst PARAMS ((char *));
865static void do_fpa_ldmstm PARAMS ((char *));
866static void do_fpa_dyadic PARAMS ((char *));
867static void do_fpa_monadic PARAMS ((char *));
868static void do_fpa_cmp PARAMS ((char *));
869static void do_fpa_from_reg PARAMS ((char *));
870static void do_fpa_to_reg PARAMS ((char *));
c9b604bd 871
bfae80f2
RE
872/* VFP instructions. */
873static void do_vfp_sp_monadic PARAMS ((char *));
874static void do_vfp_dp_monadic PARAMS ((char *));
875static void do_vfp_sp_dyadic PARAMS ((char *));
876static void do_vfp_dp_dyadic PARAMS ((char *));
877static void do_vfp_reg_from_sp PARAMS ((char *));
878static void do_vfp_sp_from_reg PARAMS ((char *));
879static void do_vfp_sp_reg2 PARAMS ((char *));
880static void do_vfp_reg_from_dp PARAMS ((char *));
881static void do_vfp_reg2_from_dp PARAMS ((char *));
882static void do_vfp_dp_from_reg PARAMS ((char *));
883static void do_vfp_dp_from_reg2 PARAMS ((char *));
884static void do_vfp_reg_from_ctrl PARAMS ((char *));
885static void do_vfp_ctrl_from_reg PARAMS ((char *));
886static void do_vfp_sp_ldst PARAMS ((char *));
887static void do_vfp_dp_ldst PARAMS ((char *));
888static void do_vfp_sp_ldstmia PARAMS ((char *));
889static void do_vfp_sp_ldstmdb PARAMS ((char *));
890static void do_vfp_dp_ldstmia PARAMS ((char *));
891static void do_vfp_dp_ldstmdb PARAMS ((char *));
892static void do_vfp_xp_ldstmia PARAMS ((char *));
893static void do_vfp_xp_ldstmdb PARAMS ((char *));
894static void do_vfp_sp_compare_z PARAMS ((char *));
895static void do_vfp_dp_compare_z PARAMS ((char *));
896static void do_vfp_dp_sp_cvt PARAMS ((char *));
897static void do_vfp_sp_dp_cvt PARAMS ((char *));
898
c9b604bd 899/* XScale. */
63e63b07
RE
900static void do_xsc_mia PARAMS ((char *));
901static void do_xsc_mar PARAMS ((char *));
902static void do_xsc_mra PARAMS ((char *));
f2b7cb0a
RE
903
904/* Maverick. */
63e63b07 905static void do_mav_binops PARAMS ((char *, int, enum arm_reg_type,
6c43fab6 906 enum arm_reg_type));
63e63b07
RE
907static void do_mav_binops_1a PARAMS ((char *));
908static void do_mav_binops_1b PARAMS ((char *));
909static void do_mav_binops_1c PARAMS ((char *));
910static void do_mav_binops_1d PARAMS ((char *));
911static void do_mav_binops_1e PARAMS ((char *));
912static void do_mav_binops_1f PARAMS ((char *));
913static void do_mav_binops_1g PARAMS ((char *));
914static void do_mav_binops_1h PARAMS ((char *));
915static void do_mav_binops_1i PARAMS ((char *));
916static void do_mav_binops_1j PARAMS ((char *));
917static void do_mav_binops_1k PARAMS ((char *));
918static void do_mav_binops_1l PARAMS ((char *));
919static void do_mav_binops_1m PARAMS ((char *));
920static void do_mav_binops_1n PARAMS ((char *));
921static void do_mav_binops_1o PARAMS ((char *));
922static void do_mav_binops_2a PARAMS ((char *));
923static void do_mav_binops_2b PARAMS ((char *));
924static void do_mav_binops_2c PARAMS ((char *));
925static void do_mav_binops_3a PARAMS ((char *));
926static void do_mav_binops_3b PARAMS ((char *));
927static void do_mav_binops_3c PARAMS ((char *));
928static void do_mav_binops_3d PARAMS ((char *));
cc8a6dd0 929static void do_mav_triple PARAMS ((char *, int, enum arm_reg_type,
6c43fab6
RE
930 enum arm_reg_type,
931 enum arm_reg_type));
63e63b07
RE
932static void do_mav_triple_4a PARAMS ((char *));
933static void do_mav_triple_4b PARAMS ((char *));
934static void do_mav_triple_5a PARAMS ((char *));
935static void do_mav_triple_5b PARAMS ((char *));
936static void do_mav_triple_5c PARAMS ((char *));
937static void do_mav_triple_5d PARAMS ((char *));
938static void do_mav_triple_5e PARAMS ((char *));
939static void do_mav_triple_5f PARAMS ((char *));
940static void do_mav_triple_5g PARAMS ((char *));
941static void do_mav_triple_5h PARAMS ((char *));
cc8a6dd0 942static void do_mav_quad PARAMS ((char *, int, enum arm_reg_type,
6c43fab6
RE
943 enum arm_reg_type,
944 enum arm_reg_type,
945 enum arm_reg_type));
63e63b07
RE
946static void do_mav_quad_6a PARAMS ((char *));
947static void do_mav_quad_6b PARAMS ((char *));
948static void do_mav_dspsc_1 PARAMS ((char *));
949static void do_mav_dspsc_2 PARAMS ((char *));
950static void do_mav_shift PARAMS ((char *, enum arm_reg_type,
6c43fab6 951 enum arm_reg_type));
63e63b07
RE
952static void do_mav_shift_1 PARAMS ((char *));
953static void do_mav_shift_2 PARAMS ((char *));
954static void do_mav_ldst PARAMS ((char *, enum arm_reg_type));
955static void do_mav_ldst_1 PARAMS ((char *));
956static void do_mav_ldst_2 PARAMS ((char *));
957static void do_mav_ldst_3 PARAMS ((char *));
958static void do_mav_ldst_4 PARAMS ((char *));
959
960static int mav_reg_required_here PARAMS ((char **, int,
6c43fab6 961 enum arm_reg_type));
63e63b07 962static int mav_parse_offset PARAMS ((char **, int *));
404ff6b5 963
90e4755a
RE
964static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *,
965 int, int));
6c43fab6
RE
966static int arm_reg_parse PARAMS ((char **, struct hash_control *));
967static enum arm_reg_type arm_reg_parse_any PARAMS ((char *));
05d2d07e 968static const struct asm_psr * arm_psr_parse PARAMS ((char **));
90e4755a
RE
969static void symbol_locate PARAMS ((symbolS *, const char *, segT, valueT,
970 fragS *));
b99bd4ef
NC
971static int add_to_lit_pool PARAMS ((void));
972static unsigned validate_immediate PARAMS ((unsigned));
90e4755a
RE
973static unsigned validate_immediate_twopart PARAMS ((unsigned int,
974 unsigned int *));
b99bd4ef
NC
975static int validate_offset_imm PARAMS ((unsigned int, int));
976static void opcode_select PARAMS ((int));
977static void end_of_line PARAMS ((char *));
978static int reg_required_here PARAMS ((char **, int));
979static int psr_required_here PARAMS ((char **));
980static int co_proc_number PARAMS ((char **));
981static int cp_opc_expr PARAMS ((char **, int, int));
982static int cp_reg_required_here PARAMS ((char **, int));
983static int fp_reg_required_here PARAMS ((char **, int));
bfae80f2
RE
984static int vfp_sp_reg_required_here PARAMS ((char **, enum vfp_sp_reg_pos));
985static int vfp_dp_reg_required_here PARAMS ((char **, enum vfp_dp_reg_pos));
986static void vfp_sp_ldstm PARAMS ((char *, enum vfp_ldstm_type));
987static void vfp_dp_ldstm PARAMS ((char *, enum vfp_ldstm_type));
988static long vfp_sp_reg_list PARAMS ((char **, enum vfp_sp_reg_pos));
989static long vfp_dp_reg_list PARAMS ((char **));
990static int vfp_psr_required_here PARAMS ((char **str));
991static const struct vfp_reg *vfp_psr_parse PARAMS ((char **str));
b99bd4ef 992static int cp_address_offset PARAMS ((char **));
bfae80f2 993static int cp_address_required_here PARAMS ((char **, int));
b99bd4ef
NC
994static int my_get_float_expression PARAMS ((char **));
995static int skip_past_comma PARAMS ((char **));
996static int walk_no_bignums PARAMS ((symbolS *));
997static int negate_data_op PARAMS ((unsigned long *, unsigned long));
998static int data_op2 PARAMS ((char **));
999static int fp_op2 PARAMS ((char **));
1000static long reg_list PARAMS ((char **));
1001static void thumb_load_store PARAMS ((char *, int, int));
1002static int decode_shift PARAMS ((char **, int));
90e4755a
RE
1003static int ldst_extend PARAMS ((char **));
1004static int ldst_extend_v4 PARAMS ((char **));
b99bd4ef 1005static void thumb_add_sub PARAMS ((char *, int));
6c43fab6
RE
1006static void insert_reg PARAMS ((const struct reg_entry *,
1007 struct hash_control *));
b99bd4ef
NC
1008static void thumb_shift PARAMS ((char *, int));
1009static void thumb_mov_compare PARAMS ((char *, int));
f2b7cb0a 1010static void build_arm_ops_hsh PARAMS ((void));
b99bd4ef
NC
1011static void set_constant_flonums PARAMS ((void));
1012static valueT md_chars_to_number PARAMS ((char *, int));
6c43fab6
RE
1013static void build_reg_hsh PARAMS ((struct reg_map *));
1014static void insert_reg_alias PARAMS ((char *, int, struct hash_control *));
1015static int create_register_alias PARAMS ((char *, char *));
f03698e6 1016static void output_inst PARAMS ((const char *));
2c20dfb2
NC
1017static int accum0_required_here PARAMS ((char **));
1018static int ld_mode_required_here PARAMS ((char **));
f2b7cb0a 1019static void do_branch25 PARAMS ((char *));
2c20dfb2 1020static symbolS * find_real_start PARAMS ((symbolS *));
b99bd4ef
NC
1021#ifdef OBJ_ELF
1022static bfd_reloc_code_real_type arm_parse_reloc PARAMS ((void));
1023#endif
1024
e16bb312
NC
1025static int wreg_required_here PARAMS ((char **, int, enum wreg_type));
1026static void do_iwmmxt_byte_addr PARAMS ((char *));
1027static void do_iwmmxt_tandc PARAMS ((char *));
1028static void do_iwmmxt_tbcst PARAMS ((char *));
1029static void do_iwmmxt_textrc PARAMS ((char *));
1030static void do_iwmmxt_textrm PARAMS ((char *));
1031static void do_iwmmxt_tinsr PARAMS ((char *));
1032static void do_iwmmxt_tmcr PARAMS ((char *));
1033static void do_iwmmxt_tmcrr PARAMS ((char *));
1034static void do_iwmmxt_tmia PARAMS ((char *));
1035static void do_iwmmxt_tmovmsk PARAMS ((char *));
1036static void do_iwmmxt_tmrc PARAMS ((char *));
1037static void do_iwmmxt_tmrrc PARAMS ((char *));
1038static void do_iwmmxt_torc PARAMS ((char *));
1039static void do_iwmmxt_waligni PARAMS ((char *));
1040static void do_iwmmxt_wmov PARAMS ((char *));
1041static void do_iwmmxt_word_addr PARAMS ((char *));
1042static void do_iwmmxt_wrwr PARAMS ((char *));
1043static void do_iwmmxt_wrwrwcg PARAMS ((char *));
1044static void do_iwmmxt_wrwrwr PARAMS ((char *));
1045static void do_iwmmxt_wshufh PARAMS ((char *));
1046static void do_iwmmxt_wzero PARAMS ((char *));
1047static int cp_byte_address_offset PARAMS ((char **));
1048static int cp_byte_address_required_here PARAMS ((char **));
1049
b99bd4ef
NC
1050/* ARM instructions take 4bytes in the object file, Thumb instructions
1051 take 2: */
1052#define INSN_SIZE 4
1053
404ff6b5 1054/* "INSN<cond> X,Y" where X:bit12, Y:bit16. */
63e63b07 1055#define MAV_MODE1 0x100c
404ff6b5
AH
1056
1057/* "INSN<cond> X,Y" where X:bit16, Y:bit12. */
63e63b07 1058#define MAV_MODE2 0x0c10
404ff6b5
AH
1059
1060/* "INSN<cond> X,Y" where X:0, Y:bit16. */
63e63b07 1061#define MAV_MODE3 0x1000
404ff6b5
AH
1062
1063/* "INSN<cond> X,Y,Z" where X:16, Y:0, Z:12. */
63e63b07 1064#define MAV_MODE4 0x0c0010
404ff6b5
AH
1065
1066/* "INSN<cond> X,Y,Z" where X:12, Y:16, Z:0. */
63e63b07 1067#define MAV_MODE5 0x00100c
404ff6b5
AH
1068
1069/* "INSN<cond> W,X,Y,Z" where W:5, X:12, Y:16, Z:0. */
63e63b07 1070#define MAV_MODE6 0x00100c05
b99bd4ef
NC
1071
1072struct asm_opcode
1073{
1074 /* Basic string to match. */
05d2d07e 1075 const char * template;
b99bd4ef
NC
1076
1077 /* Basic instruction code. */
1078 unsigned long value;
1079
90e4755a
RE
1080 /* Offset into the template where the condition code (if any) will be.
1081 If zero, then the instruction is never conditional. */
1082 unsigned cond_offset;
b99bd4ef 1083
90e4755a
RE
1084 /* Which architecture variant provides this instruction. */
1085 unsigned long variant;
b99bd4ef
NC
1086
1087 /* Function to call to parse args. */
f2b7cb0a 1088 void (* parms) PARAMS ((char *));
b99bd4ef
NC
1089};
1090
05d2d07e 1091static const struct asm_opcode insns[] =
b99bd4ef 1092{
c9b604bd 1093 /* Core ARM Instructions. */
90e4755a
RE
1094 {"and", 0xe0000000, 3, ARM_EXT_V1, do_arit},
1095 {"ands", 0xe0100000, 3, ARM_EXT_V1, do_arit},
1096 {"eor", 0xe0200000, 3, ARM_EXT_V1, do_arit},
1097 {"eors", 0xe0300000, 3, ARM_EXT_V1, do_arit},
1098 {"sub", 0xe0400000, 3, ARM_EXT_V1, do_arit},
1099 {"subs", 0xe0500000, 3, ARM_EXT_V1, do_arit},
1100 {"rsb", 0xe0600000, 3, ARM_EXT_V1, do_arit},
1101 {"rsbs", 0xe0700000, 3, ARM_EXT_V1, do_arit},
1102 {"add", 0xe0800000, 3, ARM_EXT_V1, do_arit},
1103 {"adds", 0xe0900000, 3, ARM_EXT_V1, do_arit},
1104 {"adc", 0xe0a00000, 3, ARM_EXT_V1, do_arit},
1105 {"adcs", 0xe0b00000, 3, ARM_EXT_V1, do_arit},
1106 {"sbc", 0xe0c00000, 3, ARM_EXT_V1, do_arit},
1107 {"sbcs", 0xe0d00000, 3, ARM_EXT_V1, do_arit},
1108 {"rsc", 0xe0e00000, 3, ARM_EXT_V1, do_arit},
1109 {"rscs", 0xe0f00000, 3, ARM_EXT_V1, do_arit},
1110 {"orr", 0xe1800000, 3, ARM_EXT_V1, do_arit},
1111 {"orrs", 0xe1900000, 3, ARM_EXT_V1, do_arit},
1112 {"bic", 0xe1c00000, 3, ARM_EXT_V1, do_arit},
1113 {"bics", 0xe1d00000, 3, ARM_EXT_V1, do_arit},
1114
1115 {"tst", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
1116 {"tsts", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
1117 {"tstp", 0xe110f000, 3, ARM_EXT_V1, do_cmp},
1118 {"teq", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
1119 {"teqs", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
1120 {"teqp", 0xe130f000, 3, ARM_EXT_V1, do_cmp},
1121 {"cmp", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
1122 {"cmps", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
1123 {"cmpp", 0xe150f000, 3, ARM_EXT_V1, do_cmp},
1124 {"cmn", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
1125 {"cmns", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
1126 {"cmnp", 0xe170f000, 3, ARM_EXT_V1, do_cmp},
1127
1128 {"mov", 0xe1a00000, 3, ARM_EXT_V1, do_mov},
1129 {"movs", 0xe1b00000, 3, ARM_EXT_V1, do_mov},
1130 {"mvn", 0xe1e00000, 3, ARM_EXT_V1, do_mov},
1131 {"mvns", 0xe1f00000, 3, ARM_EXT_V1, do_mov},
1132
1133 {"ldr", 0xe4100000, 3, ARM_EXT_V1, do_ldst},
1134 {"ldrb", 0xe4500000, 3, ARM_EXT_V1, do_ldst},
1135 {"ldrt", 0xe4300000, 3, ARM_EXT_V1, do_ldstt},
1136 {"ldrbt", 0xe4700000, 3, ARM_EXT_V1, do_ldstt},
1137 {"str", 0xe4000000, 3, ARM_EXT_V1, do_ldst},
1138 {"strb", 0xe4400000, 3, ARM_EXT_V1, do_ldst},
1139 {"strt", 0xe4200000, 3, ARM_EXT_V1, do_ldstt},
1140 {"strbt", 0xe4600000, 3, ARM_EXT_V1, do_ldstt},
1141
1142 {"stmia", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
1143 {"stmib", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
1144 {"stmda", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
1145 {"stmdb", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
1146 {"stmfd", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
1147 {"stmfa", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
1148 {"stmea", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
1149 {"stmed", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
1150
1151 {"ldmia", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
1152 {"ldmib", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
1153 {"ldmda", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
1154 {"ldmdb", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
1155 {"ldmfd", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
1156 {"ldmfa", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
1157 {"ldmea", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
1158 {"ldmed", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
1159
1160 {"swi", 0xef000000, 3, ARM_EXT_V1, do_swi},
b99bd4ef 1161#ifdef TE_WINCE
c9b604bd 1162 /* XXX This is the wrong place to do this. Think multi-arch. */
90e4755a
RE
1163 {"bl", 0xeb000000, 2, ARM_EXT_V1, do_branch},
1164 {"b", 0xea000000, 1, ARM_EXT_V1, do_branch},
b99bd4ef 1165#else
90e4755a
RE
1166 {"bl", 0xebfffffe, 2, ARM_EXT_V1, do_branch},
1167 {"b", 0xeafffffe, 1, ARM_EXT_V1, do_branch},
b99bd4ef
NC
1168#endif
1169
c9b604bd 1170 /* Pseudo ops. */
90e4755a
RE
1171 {"adr", 0xe28f0000, 3, ARM_EXT_V1, do_adr},
1172 {"adrl", 0xe28f0000, 3, ARM_EXT_V1, do_adrl},
1173 {"nop", 0xe1a00000, 3, ARM_EXT_V1, do_empty},
b99bd4ef 1174
c9b604bd 1175 /* ARM 2 multiplies. */
90e4755a
RE
1176 {"mul", 0xe0000090, 3, ARM_EXT_V2, do_mul},
1177 {"muls", 0xe0100090, 3, ARM_EXT_V2, do_mul},
1178 {"mla", 0xe0200090, 3, ARM_EXT_V2, do_mla},
1179 {"mlas", 0xe0300090, 3, ARM_EXT_V2, do_mla},
b99bd4ef 1180
c9b604bd 1181 /* Generic copressor instructions. */
90e4755a
RE
1182 {"cdp", 0xee000000, 3, ARM_EXT_V2, do_cdp},
1183 {"ldc", 0xec100000, 3, ARM_EXT_V2, do_lstc},
1184 {"ldcl", 0xec500000, 3, ARM_EXT_V2, do_lstc},
1185 {"stc", 0xec000000, 3, ARM_EXT_V2, do_lstc},
1186 {"stcl", 0xec400000, 3, ARM_EXT_V2, do_lstc},
1187 {"mcr", 0xee000010, 3, ARM_EXT_V2, do_co_reg},
1188 {"mrc", 0xee100010, 3, ARM_EXT_V2, do_co_reg},
c9b604bd
RE
1189
1190 /* ARM 3 - swp instructions. */
90e4755a
RE
1191 {"swp", 0xe1000090, 3, ARM_EXT_V2S, do_swap},
1192 {"swpb", 0xe1400090, 3, ARM_EXT_V2S, do_swap},
b99bd4ef 1193
c9b604bd 1194 /* ARM 6 Status register instructions. */
90e4755a
RE
1195 {"mrs", 0xe10f0000, 3, ARM_EXT_V3, do_mrs},
1196 {"msr", 0xe120f000, 3, ARM_EXT_V3, do_msr},
1197 /* ScottB: our code uses 0xe128f000 for msr.
c9b604bd 1198 NickC: but this is wrong because the bits 16 through 19 are
90e4755a 1199 handled by the PSR_xxx defines above. */
b99bd4ef 1200
f2b7cb0a 1201 /* ARM 7M long multiplies. */
90e4755a
RE
1202 {"smull", 0xe0c00090, 5, ARM_EXT_V3M, do_mull},
1203 {"smulls", 0xe0d00090, 5, ARM_EXT_V3M, do_mull},
1204 {"umull", 0xe0800090, 5, ARM_EXT_V3M, do_mull},
1205 {"umulls", 0xe0900090, 5, ARM_EXT_V3M, do_mull},
1206 {"smlal", 0xe0e00090, 5, ARM_EXT_V3M, do_mull},
1207 {"smlals", 0xe0f00090, 5, ARM_EXT_V3M, do_mull},
1208 {"umlal", 0xe0a00090, 5, ARM_EXT_V3M, do_mull},
1209 {"umlals", 0xe0b00090, 5, ARM_EXT_V3M, do_mull},
1210
1211 /* ARM Architecture 4. */
1212 {"ldrh", 0xe01000b0, 3, ARM_EXT_V4, do_ldstv4},
1213 {"ldrsh", 0xe01000f0, 3, ARM_EXT_V4, do_ldstv4},
1214 {"ldrsb", 0xe01000d0, 3, ARM_EXT_V4, do_ldstv4},
1215 {"strh", 0xe00000b0, 3, ARM_EXT_V4, do_ldstv4},
b99bd4ef 1216
c9b604bd 1217 /* ARM Architecture 4T. */
cc8a6dd0 1218 /* Note: bx (and blx) are required on V5, even if the processor does
90e4755a
RE
1219 not support Thumb. */
1220 {"bx", 0xe12fff10, 2, ARM_EXT_V4T | ARM_EXT_V5, do_bx},
1221
ea6ef066 1222 /* ARM Architecture 5T. */
90e4755a
RE
1223 /* Note: blx has 2 variants, so the .value is set dynamically.
1224 Only one of the variants has conditional execution. */
1225 {"blx", 0xe0000000, 3, ARM_EXT_V5, do_blx},
1226 {"clz", 0xe16f0f10, 3, ARM_EXT_V5, do_clz},
1227 {"bkpt", 0xe1200070, 0, ARM_EXT_V5, do_bkpt},
1228 {"ldc2", 0xfc100000, 0, ARM_EXT_V5, do_lstc2},
1229 {"ldc2l", 0xfc500000, 0, ARM_EXT_V5, do_lstc2},
1230 {"stc2", 0xfc000000, 0, ARM_EXT_V5, do_lstc2},
1231 {"stc2l", 0xfc400000, 0, ARM_EXT_V5, do_lstc2},
1232 {"cdp2", 0xfe000000, 0, ARM_EXT_V5, do_cdp2},
1233 {"mcr2", 0xfe000010, 0, ARM_EXT_V5, do_co_reg2},
1234 {"mrc2", 0xfe100010, 0, ARM_EXT_V5, do_co_reg2},
1235
ea6ef066 1236 /* ARM Architecture 5TExP. */
90e4755a
RE
1237 {"smlabb", 0xe1000080, 6, ARM_EXT_V5ExP, do_smla},
1238 {"smlatb", 0xe10000a0, 6, ARM_EXT_V5ExP, do_smla},
1239 {"smlabt", 0xe10000c0, 6, ARM_EXT_V5ExP, do_smla},
1240 {"smlatt", 0xe10000e0, 6, ARM_EXT_V5ExP, do_smla},
1241
1242 {"smlawb", 0xe1200080, 6, ARM_EXT_V5ExP, do_smla},
1243 {"smlawt", 0xe12000c0, 6, ARM_EXT_V5ExP, do_smla},
1244
1245 {"smlalbb", 0xe1400080, 7, ARM_EXT_V5ExP, do_smlal},
1246 {"smlaltb", 0xe14000a0, 7, ARM_EXT_V5ExP, do_smlal},
1247 {"smlalbt", 0xe14000c0, 7, ARM_EXT_V5ExP, do_smlal},
1248 {"smlaltt", 0xe14000e0, 7, ARM_EXT_V5ExP, do_smlal},
1249
1250 {"smulbb", 0xe1600080, 6, ARM_EXT_V5ExP, do_smul},
1251 {"smultb", 0xe16000a0, 6, ARM_EXT_V5ExP, do_smul},
1252 {"smulbt", 0xe16000c0, 6, ARM_EXT_V5ExP, do_smul},
1253 {"smultt", 0xe16000e0, 6, ARM_EXT_V5ExP, do_smul},
1254
1255 {"smulwb", 0xe12000a0, 6, ARM_EXT_V5ExP, do_smul},
1256 {"smulwt", 0xe12000e0, 6, ARM_EXT_V5ExP, do_smul},
1257
1258 {"qadd", 0xe1000050, 4, ARM_EXT_V5ExP, do_qadd},
1259 {"qdadd", 0xe1400050, 5, ARM_EXT_V5ExP, do_qadd},
1260 {"qsub", 0xe1200050, 4, ARM_EXT_V5ExP, do_qadd},
1261 {"qdsub", 0xe1600050, 5, ARM_EXT_V5ExP, do_qadd},
c9b604bd 1262
ea6ef066 1263 /* ARM Architecture 5TE. */
90e4755a
RE
1264 {"pld", 0xf450f000, 0, ARM_EXT_V5E, do_pld},
1265 {"ldrd", 0xe00000d0, 3, ARM_EXT_V5E, do_ldrd},
1266 {"strd", 0xe00000f0, 3, ARM_EXT_V5E, do_ldrd},
1267
1268 {"mcrr", 0xec400000, 4, ARM_EXT_V5E, do_co_reg2c},
1269 {"mrrc", 0xec500000, 4, ARM_EXT_V5E, do_co_reg2c},
404ff6b5 1270
ea6ef066
RE
1271 /* ARM Architecture 5TEJ. */
1272 {"bxj", 0xe12fff20, 3, ARM_EXT_V5J, do_bxj},
1273
c9b604bd 1274 /* Core FPA instruction set (V1). */
90e4755a
RE
1275 {"wfs", 0xee200110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1276 {"rfs", 0xee300110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1277 {"wfc", 0xee400110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1278 {"rfc", 0xee500110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1279
1280 {"ldfs", 0xec100100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1281 {"ldfd", 0xec108100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1282 {"ldfe", 0xec500100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1283 {"ldfp", 0xec508100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1284
1285 {"stfs", 0xec000100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1286 {"stfd", 0xec008100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1287 {"stfe", 0xec400100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1288 {"stfp", 0xec408100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1289
1290 {"mvfs", 0xee008100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1291 {"mvfsp", 0xee008120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1292 {"mvfsm", 0xee008140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1293 {"mvfsz", 0xee008160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1294 {"mvfd", 0xee008180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1295 {"mvfdp", 0xee0081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1296 {"mvfdm", 0xee0081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1297 {"mvfdz", 0xee0081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1298 {"mvfe", 0xee088100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1299 {"mvfep", 0xee088120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1300 {"mvfem", 0xee088140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1301 {"mvfez", 0xee088160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1302
1303 {"mnfs", 0xee108100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1304 {"mnfsp", 0xee108120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1305 {"mnfsm", 0xee108140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1306 {"mnfsz", 0xee108160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1307 {"mnfd", 0xee108180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1308 {"mnfdp", 0xee1081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1309 {"mnfdm", 0xee1081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1310 {"mnfdz", 0xee1081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1311 {"mnfe", 0xee188100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1312 {"mnfep", 0xee188120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1313 {"mnfem", 0xee188140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1314 {"mnfez", 0xee188160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1315
1316 {"abss", 0xee208100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1317 {"abssp", 0xee208120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1318 {"abssm", 0xee208140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1319 {"abssz", 0xee208160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1320 {"absd", 0xee208180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1321 {"absdp", 0xee2081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1322 {"absdm", 0xee2081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1323 {"absdz", 0xee2081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1324 {"abse", 0xee288100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1325 {"absep", 0xee288120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1326 {"absem", 0xee288140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1327 {"absez", 0xee288160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1328
1329 {"rnds", 0xee308100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1330 {"rndsp", 0xee308120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1331 {"rndsm", 0xee308140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1332 {"rndsz", 0xee308160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1333 {"rndd", 0xee308180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1334 {"rnddp", 0xee3081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1335 {"rnddm", 0xee3081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1336 {"rnddz", 0xee3081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1337 {"rnde", 0xee388100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1338 {"rndep", 0xee388120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1339 {"rndem", 0xee388140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1340 {"rndez", 0xee388160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1341
1342 {"sqts", 0xee408100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1343 {"sqtsp", 0xee408120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1344 {"sqtsm", 0xee408140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1345 {"sqtsz", 0xee408160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1346 {"sqtd", 0xee408180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1347 {"sqtdp", 0xee4081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1348 {"sqtdm", 0xee4081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1349 {"sqtdz", 0xee4081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1350 {"sqte", 0xee488100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1351 {"sqtep", 0xee488120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1352 {"sqtem", 0xee488140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1353 {"sqtez", 0xee488160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1354
1355 {"logs", 0xee508100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1356 {"logsp", 0xee508120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1357 {"logsm", 0xee508140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1358 {"logsz", 0xee508160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1359 {"logd", 0xee508180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1360 {"logdp", 0xee5081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1361 {"logdm", 0xee5081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1362 {"logdz", 0xee5081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1363 {"loge", 0xee588100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1364 {"logep", 0xee588120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1365 {"logem", 0xee588140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1366 {"logez", 0xee588160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1367
1368 {"lgns", 0xee608100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1369 {"lgnsp", 0xee608120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1370 {"lgnsm", 0xee608140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1371 {"lgnsz", 0xee608160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1372 {"lgnd", 0xee608180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1373 {"lgndp", 0xee6081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1374 {"lgndm", 0xee6081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1375 {"lgndz", 0xee6081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1376 {"lgne", 0xee688100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1377 {"lgnep", 0xee688120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1378 {"lgnem", 0xee688140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1379 {"lgnez", 0xee688160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1380
1381 {"exps", 0xee708100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1382 {"expsp", 0xee708120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1383 {"expsm", 0xee708140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1384 {"expsz", 0xee708160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1385 {"expd", 0xee708180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1386 {"expdp", 0xee7081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1387 {"expdm", 0xee7081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1388 {"expdz", 0xee7081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1389 {"expe", 0xee788100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1390 {"expep", 0xee788120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1391 {"expem", 0xee788140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1392 {"expdz", 0xee788160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1393
1394 {"sins", 0xee808100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1395 {"sinsp", 0xee808120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1396 {"sinsm", 0xee808140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1397 {"sinsz", 0xee808160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1398 {"sind", 0xee808180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1399 {"sindp", 0xee8081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1400 {"sindm", 0xee8081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1401 {"sindz", 0xee8081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1402 {"sine", 0xee888100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1403 {"sinep", 0xee888120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1404 {"sinem", 0xee888140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1405 {"sinez", 0xee888160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1406
1407 {"coss", 0xee908100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1408 {"cossp", 0xee908120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1409 {"cossm", 0xee908140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1410 {"cossz", 0xee908160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1411 {"cosd", 0xee908180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1412 {"cosdp", 0xee9081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1413 {"cosdm", 0xee9081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1414 {"cosdz", 0xee9081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1415 {"cose", 0xee988100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1416 {"cosep", 0xee988120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1417 {"cosem", 0xee988140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1418 {"cosez", 0xee988160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1419
1420 {"tans", 0xeea08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1421 {"tansp", 0xeea08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1422 {"tansm", 0xeea08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1423 {"tansz", 0xeea08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1424 {"tand", 0xeea08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1425 {"tandp", 0xeea081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1426 {"tandm", 0xeea081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1427 {"tandz", 0xeea081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1428 {"tane", 0xeea88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1429 {"tanep", 0xeea88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1430 {"tanem", 0xeea88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1431 {"tanez", 0xeea88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1432
1433 {"asns", 0xeeb08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1434 {"asnsp", 0xeeb08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1435 {"asnsm", 0xeeb08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1436 {"asnsz", 0xeeb08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1437 {"asnd", 0xeeb08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1438 {"asndp", 0xeeb081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1439 {"asndm", 0xeeb081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1440 {"asndz", 0xeeb081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1441 {"asne", 0xeeb88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1442 {"asnep", 0xeeb88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1443 {"asnem", 0xeeb88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1444 {"asnez", 0xeeb88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1445
1446 {"acss", 0xeec08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1447 {"acssp", 0xeec08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1448 {"acssm", 0xeec08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1449 {"acssz", 0xeec08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1450 {"acsd", 0xeec08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1451 {"acsdp", 0xeec081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1452 {"acsdm", 0xeec081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1453 {"acsdz", 0xeec081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1454 {"acse", 0xeec88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1455 {"acsep", 0xeec88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1456 {"acsem", 0xeec88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1457 {"acsez", 0xeec88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1458
1459 {"atns", 0xeed08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1460 {"atnsp", 0xeed08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1461 {"atnsm", 0xeed08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1462 {"atnsz", 0xeed08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1463 {"atnd", 0xeed08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1464 {"atndp", 0xeed081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1465 {"atndm", 0xeed081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1466 {"atndz", 0xeed081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1467 {"atne", 0xeed88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1468 {"atnep", 0xeed88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1469 {"atnem", 0xeed88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1470 {"atnez", 0xeed88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1471
1472 {"urds", 0xeee08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1473 {"urdsp", 0xeee08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1474 {"urdsm", 0xeee08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1475 {"urdsz", 0xeee08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1476 {"urdd", 0xeee08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1477 {"urddp", 0xeee081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1478 {"urddm", 0xeee081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1479 {"urddz", 0xeee081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1480 {"urde", 0xeee88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1481 {"urdep", 0xeee88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1482 {"urdem", 0xeee88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1483 {"urdez", 0xeee88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1484
1485 {"nrms", 0xeef08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1486 {"nrmsp", 0xeef08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1487 {"nrmsm", 0xeef08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1488 {"nrmsz", 0xeef08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1489 {"nrmd", 0xeef08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1490 {"nrmdp", 0xeef081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1491 {"nrmdm", 0xeef081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1492 {"nrmdz", 0xeef081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1493 {"nrme", 0xeef88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1494 {"nrmep", 0xeef88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1495 {"nrmem", 0xeef88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1496 {"nrmez", 0xeef88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1497
1498 {"adfs", 0xee000100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1499 {"adfsp", 0xee000120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1500 {"adfsm", 0xee000140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1501 {"adfsz", 0xee000160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1502 {"adfd", 0xee000180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1503 {"adfdp", 0xee0001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1504 {"adfdm", 0xee0001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1505 {"adfdz", 0xee0001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1506 {"adfe", 0xee080100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1507 {"adfep", 0xee080120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1508 {"adfem", 0xee080140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1509 {"adfez", 0xee080160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1510
1511 {"sufs", 0xee200100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1512 {"sufsp", 0xee200120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1513 {"sufsm", 0xee200140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1514 {"sufsz", 0xee200160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1515 {"sufd", 0xee200180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1516 {"sufdp", 0xee2001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1517 {"sufdm", 0xee2001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1518 {"sufdz", 0xee2001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1519 {"sufe", 0xee280100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1520 {"sufep", 0xee280120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1521 {"sufem", 0xee280140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1522 {"sufez", 0xee280160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1523
1524 {"rsfs", 0xee300100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1525 {"rsfsp", 0xee300120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1526 {"rsfsm", 0xee300140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1527 {"rsfsz", 0xee300160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1528 {"rsfd", 0xee300180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1529 {"rsfdp", 0xee3001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1530 {"rsfdm", 0xee3001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1531 {"rsfdz", 0xee3001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1532 {"rsfe", 0xee380100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1533 {"rsfep", 0xee380120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1534 {"rsfem", 0xee380140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1535 {"rsfez", 0xee380160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1536
1537 {"mufs", 0xee100100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1538 {"mufsp", 0xee100120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1539 {"mufsm", 0xee100140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1540 {"mufsz", 0xee100160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1541 {"mufd", 0xee100180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1542 {"mufdp", 0xee1001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1543 {"mufdm", 0xee1001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1544 {"mufdz", 0xee1001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1545 {"mufe", 0xee180100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1546 {"mufep", 0xee180120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1547 {"mufem", 0xee180140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1548 {"mufez", 0xee180160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1549
1550 {"dvfs", 0xee400100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1551 {"dvfsp", 0xee400120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1552 {"dvfsm", 0xee400140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1553 {"dvfsz", 0xee400160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1554 {"dvfd", 0xee400180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1555 {"dvfdp", 0xee4001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1556 {"dvfdm", 0xee4001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1557 {"dvfdz", 0xee4001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1558 {"dvfe", 0xee480100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1559 {"dvfep", 0xee480120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1560 {"dvfem", 0xee480140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1561 {"dvfez", 0xee480160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1562
1563 {"rdfs", 0xee500100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1564 {"rdfsp", 0xee500120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1565 {"rdfsm", 0xee500140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1566 {"rdfsz", 0xee500160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1567 {"rdfd", 0xee500180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1568 {"rdfdp", 0xee5001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1569 {"rdfdm", 0xee5001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1570 {"rdfdz", 0xee5001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1571 {"rdfe", 0xee580100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1572 {"rdfep", 0xee580120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1573 {"rdfem", 0xee580140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1574 {"rdfez", 0xee580160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1575
1576 {"pows", 0xee600100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1577 {"powsp", 0xee600120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1578 {"powsm", 0xee600140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1579 {"powsz", 0xee600160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1580 {"powd", 0xee600180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1581 {"powdp", 0xee6001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1582 {"powdm", 0xee6001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1583 {"powdz", 0xee6001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1584 {"powe", 0xee680100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1585 {"powep", 0xee680120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1586 {"powem", 0xee680140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1587 {"powez", 0xee680160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1588
1589 {"rpws", 0xee700100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1590 {"rpwsp", 0xee700120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1591 {"rpwsm", 0xee700140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1592 {"rpwsz", 0xee700160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1593 {"rpwd", 0xee700180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1594 {"rpwdp", 0xee7001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1595 {"rpwdm", 0xee7001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1596 {"rpwdz", 0xee7001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1597 {"rpwe", 0xee780100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1598 {"rpwep", 0xee780120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1599 {"rpwem", 0xee780140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1600 {"rpwez", 0xee780160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1601
1602 {"rmfs", 0xee800100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1603 {"rmfsp", 0xee800120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1604 {"rmfsm", 0xee800140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1605 {"rmfsz", 0xee800160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1606 {"rmfd", 0xee800180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1607 {"rmfdp", 0xee8001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1608 {"rmfdm", 0xee8001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1609 {"rmfdz", 0xee8001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1610 {"rmfe", 0xee880100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1611 {"rmfep", 0xee880120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1612 {"rmfem", 0xee880140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1613 {"rmfez", 0xee880160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1614
1615 {"fmls", 0xee900100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1616 {"fmlsp", 0xee900120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1617 {"fmlsm", 0xee900140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1618 {"fmlsz", 0xee900160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1619 {"fmld", 0xee900180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1620 {"fmldp", 0xee9001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1621 {"fmldm", 0xee9001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1622 {"fmldz", 0xee9001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1623 {"fmle", 0xee980100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1624 {"fmlep", 0xee980120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1625 {"fmlem", 0xee980140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1626 {"fmlez", 0xee980160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1627
1628 {"fdvs", 0xeea00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1629 {"fdvsp", 0xeea00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1630 {"fdvsm", 0xeea00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1631 {"fdvsz", 0xeea00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1632 {"fdvd", 0xeea00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1633 {"fdvdp", 0xeea001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1634 {"fdvdm", 0xeea001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1635 {"fdvdz", 0xeea001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1636 {"fdve", 0xeea80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1637 {"fdvep", 0xeea80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1638 {"fdvem", 0xeea80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1639 {"fdvez", 0xeea80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1640
1641 {"frds", 0xeeb00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1642 {"frdsp", 0xeeb00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1643 {"frdsm", 0xeeb00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1644 {"frdsz", 0xeeb00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1645 {"frdd", 0xeeb00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1646 {"frddp", 0xeeb001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1647 {"frddm", 0xeeb001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1648 {"frddz", 0xeeb001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1649 {"frde", 0xeeb80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1650 {"frdep", 0xeeb80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1651 {"frdem", 0xeeb80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1652 {"frdez", 0xeeb80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1653
1654 {"pols", 0xeec00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1655 {"polsp", 0xeec00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1656 {"polsm", 0xeec00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1657 {"polsz", 0xeec00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1658 {"pold", 0xeec00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1659 {"poldp", 0xeec001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1660 {"poldm", 0xeec001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1661 {"poldz", 0xeec001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1662 {"pole", 0xeec80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1663 {"polep", 0xeec80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1664 {"polem", 0xeec80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1665 {"polez", 0xeec80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1666
1667 {"cmf", 0xee90f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1668 {"cmfe", 0xeed0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1669 {"cnf", 0xeeb0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1670 {"cnfe", 0xeef0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1671 /* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should
1672 not be an optional suffix, but part of the instruction. To be
1673 compatible, we accept either. */
1674 {"cmfe", 0xeed0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
1675 {"cnfe", 0xeef0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
1676
1677 {"flts", 0xee000110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1678 {"fltsp", 0xee000130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1679 {"fltsm", 0xee000150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1680 {"fltsz", 0xee000170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1681 {"fltd", 0xee000190, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1682 {"fltdp", 0xee0001b0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1683 {"fltdm", 0xee0001d0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1684 {"fltdz", 0xee0001f0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1685 {"flte", 0xee080110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1686 {"fltep", 0xee080130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1687 {"fltem", 0xee080150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1688 {"fltez", 0xee080170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1689
1690 /* The implementation of the FIX instruction is broken on some
1691 assemblers, in that it accepts a precision specifier as well as a
1692 rounding specifier, despite the fact that this is meaningless.
1693 To be more compatible, we accept it as well, though of course it
1694 does not set any bits. */
1695 {"fix", 0xee100110, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1696 {"fixp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1697 {"fixm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1698 {"fixz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1699 {"fixsp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1700 {"fixsm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1701 {"fixsz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1702 {"fixdp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1703 {"fixdm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1704 {"fixdz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1705 {"fixep", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1706 {"fixem", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1707 {"fixez", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
c9b604bd
RE
1708
1709 /* Instructions that were new with the real FPA, call them V2. */
90e4755a
RE
1710 {"lfm", 0xec100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1711 {"lfmfd", 0xec900200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1712 {"lfmea", 0xed100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1713 {"sfm", 0xec000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1714 {"sfmfd", 0xed000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1715 {"sfmea", 0xec800200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
c9b604bd 1716
bfae80f2
RE
1717 /* VFP V1xD (single precision). */
1718 /* Moves and type conversions. */
1719 {"fcpys", 0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1720 {"fmrs", 0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp},
1721 {"fmsr", 0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg},
1722 {"fmstat", 0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty},
1723 {"fsitos", 0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1724 {"fuitos", 0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1725 {"ftosis", 0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1726 {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1727 {"ftouis", 0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1728 {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1729 {"fmrx", 0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl},
1730 {"fmxr", 0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg},
1731
1732 /* Memory operations. */
1733 {"flds", 0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
1734 {"fsts", 0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
1735 {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1736 {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1737 {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1738 {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1739 {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1740 {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1741 {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1742 {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1743 {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1744 {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1745 {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1746 {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1747 {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1748 {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1749 {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1750 {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1751
1752 /* Monadic operations. */
1753 {"fabss", 0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1754 {"fnegs", 0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1755 {"fsqrts", 0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1756
1757 /* Dyadic operations. */
1758 {"fadds", 0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1759 {"fsubs", 0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1760 {"fmuls", 0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1761 {"fdivs", 0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1762 {"fmacs", 0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1763 {"fmscs", 0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1764 {"fnmuls", 0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1765 {"fnmacs", 0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1766 {"fnmscs", 0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1767
1768 /* Comparisons. */
1769 {"fcmps", 0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1770 {"fcmpzs", 0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
1771 {"fcmpes", 0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1772 {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
1773
1774 /* VFP V1 (Double precision). */
1775 /* Moves and type conversions. */
1776 {"fcpyd", 0xeeb00b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1777 {"fcvtds", 0xeeb70ac0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
1778 {"fcvtsd", 0xeeb70bc0, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1779 {"fmdhr", 0xee200b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
1780 {"fmdlr", 0xee000b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
1781 {"fmrdh", 0xee300b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
1782 {"fmrdl", 0xee100b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
1783 {"fsitod", 0xeeb80bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
1784 {"fuitod", 0xeeb80b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
1785 {"ftosid", 0xeebd0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1786 {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1787 {"ftouid", 0xeebc0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1788 {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1789
1790 /* Memory operations. */
1791 {"fldd", 0xed100b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
1792 {"fstd", 0xed000b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
1793 {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1794 {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1795 {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1796 {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1797 {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1798 {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1799 {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1800 {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1801
1802 /* Monadic operations. */
1803 {"fabsd", 0xeeb00bc0, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1804 {"fnegd", 0xeeb10b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1805 {"fsqrtd", 0xeeb10bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1806
1807 /* Dyadic operations. */
1808 {"faddd", 0xee300b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1809 {"fsubd", 0xee300b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1810 {"fmuld", 0xee200b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1811 {"fdivd", 0xee800b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1812 {"fmacd", 0xee000b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1813 {"fmscd", 0xee100b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1814 {"fnmuld", 0xee200b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1815 {"fnmacd", 0xee000b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1816 {"fnmscd", 0xee100b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1817
1818 /* Comparisons. */
1819 {"fcmpd", 0xeeb40b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1820 {"fcmpzd", 0xeeb50b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
1821 {"fcmped", 0xeeb40bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1822 {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
1823
1824 /* VFP V2. */
1825 {"fmsrr", 0xec400a10, 5, FPU_VFP_EXT_V2, do_vfp_sp_reg2},
1826 {"fmrrs", 0xec500a10, 5, FPU_VFP_EXT_V2, do_vfp_sp_reg2},
1827 {"fmdrr", 0xec400b10, 5, FPU_VFP_EXT_V2, do_vfp_dp_from_reg2},
1828 {"fmrrd", 0xec500b10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_dp},
1829
c9b604bd 1830 /* Intel XScale extensions to ARM V5 ISA. (All use CP0). */
63e63b07
RE
1831 {"mia", 0xee200010, 3, ARM_CEXT_XSCALE, do_xsc_mia},
1832 {"miaph", 0xee280010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1833 {"miabb", 0xee2c0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1834 {"miabt", 0xee2d0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1835 {"miatb", 0xee2e0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1836 {"miatt", 0xee2f0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1837 {"mar", 0xec400000, 3, ARM_CEXT_XSCALE, do_xsc_mar},
1838 {"mra", 0xec500000, 3, ARM_CEXT_XSCALE, do_xsc_mra},
1839
5a6c6817
NC
1840 /* Intel Wireless MMX technology instructions. */
1841 {"tandcb", 0xee130130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
1842 {"tandch", 0xee530130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
1843 {"tandcw", 0xee930130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
1844 {"tbcstb", 0xee400010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
1845 {"tbcsth", 0xee400050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
1846 {"tbcstw", 0xee400090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
1847 {"textrcb", 0xee130170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
1848 {"textrch", 0xee530170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
1849 {"textrcw", 0xee930170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
1850 {"textrmub", 0xee100070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1851 {"textrmuh", 0xee500070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1852 {"textrmuw", 0xee900070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1853 {"textrmsb", 0xee100078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1854 {"textrmsh", 0xee500078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1855 {"textrmsw", 0xee900078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1856 {"tinsrb", 0xee600010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
1857 {"tinsrh", 0xee600050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
1858 {"tinsrw", 0xee600090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
1859 {"tmcr", 0xee000110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmcr},
1860 {"tmcrr", 0xec400000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmcrr},
1861 {"tmia", 0xee200010, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1862 {"tmiaph", 0xee280010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1863 {"tmiabb", 0xee2c0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1864 {"tmiabt", 0xee2d0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1865 {"tmiatb", 0xee2e0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1866 {"tmiatt", 0xee2f0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1867 {"tmovmskb", 0xee100030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
1868 {"tmovmskh", 0xee500030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
1869 {"tmovmskw", 0xee900030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
1870 {"tmrc", 0xee100110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmrc},
1871 {"tmrrc", 0xec500000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmrrc},
1872 {"torcb", 0xee130150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
1873 {"torch", 0xee530150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
1874 {"torcw", 0xee930150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
1875 {"waccb", 0xee0001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1876 {"wacch", 0xee4001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1877 {"waccw", 0xee8001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1878 {"waddbss", 0xee300180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1879 {"waddb", 0xee000180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1880 {"waddbus", 0xee100180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1881 {"waddhss", 0xee700180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1882 {"waddh", 0xee400180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1883 {"waddhus", 0xee500180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1884 {"waddwss", 0xeeb00180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1885 {"waddw", 0xee800180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1886 {"waddwus", 0xee900180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1887 {"waligni", 0xee000020, 7, ARM_CEXT_IWMMXT, do_iwmmxt_waligni},
1888 {"walignr0", 0xee800020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1889 {"walignr1", 0xee900020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1890 {"walignr2", 0xeea00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1891 {"walignr3", 0xeeb00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1892 {"wand", 0xee200000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1893 {"wandn", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1894 {"wavg2b", 0xee800000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1895 {"wavg2br", 0xee900000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1896 {"wavg2h", 0xeec00000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1897 {"wavg2hr", 0xeed00000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1898 {"wcmpeqb", 0xee000060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1899 {"wcmpeqh", 0xee400060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1900 {"wcmpeqw", 0xee800060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1901 {"wcmpgtub", 0xee100060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1902 {"wcmpgtuh", 0xee500060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1903 {"wcmpgtuw", 0xee900060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1904 {"wcmpgtsb", 0xee300060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1905 {"wcmpgtsh", 0xee700060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1906 {"wcmpgtsw", 0xeeb00060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1907 {"wldrb", 0xec100000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1908 {"wldrh", 0xec100100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1909 {"wldrw", 0xec100200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1910 {"wldrd", 0xec100300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1911 {"wmacs", 0xee600100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1912 {"wmacsz", 0xee700100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1913 {"wmacu", 0xee400100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1914 {"wmacuz", 0xee500100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1915 {"wmadds", 0xeea00100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1916 {"wmaddu", 0xee800100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1917 {"wmaxsb", 0xee200160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1918 {"wmaxsh", 0xee600160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1919 {"wmaxsw", 0xeea00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1920 {"wmaxub", 0xee000160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1921 {"wmaxuh", 0xee400160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1922 {"wmaxuw", 0xee800160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1923 {"wminsb", 0xee300160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1924 {"wminsh", 0xee700160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1925 {"wminsw", 0xeeb00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1926 {"wminub", 0xee100160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1927 {"wminuh", 0xee500160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1928 {"wminuw", 0xee900160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1929 {"wmov", 0xee000000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wmov},
1930 {"wmulsm", 0xee300100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1931 {"wmulsl", 0xee200100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1932 {"wmulum", 0xee100100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1933 {"wmulul", 0xee000100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1934 {"wor", 0xee000000, 3, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1935 {"wpackhss", 0xee700080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1936 {"wpackhus", 0xee500080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1937 {"wpackwss", 0xeeb00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1938 {"wpackwus", 0xee900080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1939 {"wpackdss", 0xeef00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1940 {"wpackdus", 0xeed00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1941 {"wrorh", 0xee700040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1942 {"wrorhg", 0xee700148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1943 {"wrorw", 0xeeb00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1944 {"wrorwg", 0xeeb00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1945 {"wrord", 0xeef00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1946 {"wrordg", 0xeef00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1947 {"wsadb", 0xee000120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1948 {"wsadbz", 0xee100120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1949 {"wsadh", 0xee400120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1950 {"wsadhz", 0xee500120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1951 {"wshufh", 0xee0001e0, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wshufh},
1952 {"wsllh", 0xee500040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1953 {"wsllhg", 0xee500148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1954 {"wsllw", 0xee900040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1955 {"wsllwg", 0xee900148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1956 {"wslld", 0xeed00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1957 {"wslldg", 0xeed00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1958 {"wsrah", 0xee400040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1959 {"wsrahg", 0xee400148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1960 {"wsraw", 0xee800040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1961 {"wsrawg", 0xee800148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1962 {"wsrad", 0xeec00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1963 {"wsradg", 0xeec00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1964 {"wsrlh", 0xee600040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1965 {"wsrlhg", 0xee600148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1966 {"wsrlw", 0xeea00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1967 {"wsrlwg", 0xeea00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1968 {"wsrld", 0xeee00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1969 {"wsrldg", 0xeee00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1970 {"wstrb", 0xec000000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1971 {"wstrh", 0xec000100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1972 {"wstrw", 0xec000200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1973 {"wstrd", 0xec000300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1974 {"wsubbss", 0xee3001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1975 {"wsubb", 0xee0001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1976 {"wsubbus", 0xee1001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1977 {"wsubhss", 0xee7001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1978 {"wsubh", 0xee4001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1979 {"wsubhus", 0xee5001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1980 {"wsubwss", 0xeeb001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1981 {"wsubw", 0xee8001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1982 {"wsubwus", 0xee9001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1983 {"wunpckehub", 0xee0000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1984 {"wunpckehuh", 0xee4000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1985 {"wunpckehuw", 0xee8000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1986 {"wunpckehsb", 0xee2000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1987 {"wunpckehsh", 0xee6000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1988 {"wunpckehsw", 0xeea000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1989 {"wunpckihb", 0xee1000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1990 {"wunpckihh", 0xee5000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1991 {"wunpckihw", 0xee9000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1992 {"wunpckelub", 0xee0000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1993 {"wunpckeluh", 0xee4000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1994 {"wunpckeluw", 0xee8000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1995 {"wunpckelsb", 0xee2000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1996 {"wunpckelsh", 0xee6000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1997 {"wunpckelsw", 0xeea000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1998 {"wunpckilb", 0xee1000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1999 {"wunpckilh", 0xee5000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
2000 {"wunpckilw", 0xee9000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
2001 {"wxor", 0xee100000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
2002 {"wzero", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wzero},
2003
63e63b07
RE
2004 /* Cirrus Maverick instructions. */
2005 {"cfldrs", 0xec100400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
2006 {"cfldrd", 0xec500400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
2007 {"cfldr32", 0xec100500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
2008 {"cfldr64", 0xec500500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
2009 {"cfstrs", 0xec000400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
2010 {"cfstrd", 0xec400400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
2011 {"cfstr32", 0xec000500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
2012 {"cfstr64", 0xec400500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
2013 {"cfmvsr", 0xee000450, 6, ARM_CEXT_MAVERICK, do_mav_binops_2a},
2014 {"cfmvrs", 0xee100450, 6, ARM_CEXT_MAVERICK, do_mav_binops_1a},
2015 {"cfmvdlr", 0xee000410, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
2016 {"cfmvrdl", 0xee100410, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
2017 {"cfmvdhr", 0xee000430, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
2018 {"cfmvrdh", 0xee100430, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
2019 {"cfmv64lr", 0xee000510, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
2020 {"cfmvr64l", 0xee100510, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
2021 {"cfmv64hr", 0xee000530, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
2022 {"cfmvr64h", 0xee100530, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
2023 {"cfmval32", 0xee100610, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2024 {"cfmv32al", 0xee000610, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2025 {"cfmvam32", 0xee100630, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2026 {"cfmv32am", 0xee000630, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2027 {"cfmvah32", 0xee100650, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2028 {"cfmv32ah", 0xee000650, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2029 {"cfmva32", 0xee100670, 7, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2030 {"cfmv32a", 0xee000670, 7, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2031 {"cfmva64", 0xee100690, 7, ARM_CEXT_MAVERICK, do_mav_binops_3c},
2032 {"cfmv64a", 0xee000690, 7, ARM_CEXT_MAVERICK, do_mav_binops_3d},
2033 {"cfmvsc32", 0xee1006b0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_1},
2034 {"cfmv32sc", 0xee0006b0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_2},
2035 {"cfcpys", 0xee000400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
2036 {"cfcpyd", 0xee000420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
2037 {"cfcvtsd", 0xee000460, 7, ARM_CEXT_MAVERICK, do_mav_binops_1f},
2038 {"cfcvtds", 0xee000440, 7, ARM_CEXT_MAVERICK, do_mav_binops_1g},
2039 {"cfcvt32s", 0xee000480, 8, ARM_CEXT_MAVERICK, do_mav_binops_1h},
2040 {"cfcvt32d", 0xee0004a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1i},
2041 {"cfcvt64s", 0xee0004c0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1j},
2042 {"cfcvt64d", 0xee0004e0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1k},
2043 {"cfcvts32", 0xee100580, 8, ARM_CEXT_MAVERICK, do_mav_binops_1l},
2044 {"cfcvtd32", 0xee1005a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1m},
2045 {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l},
2046 {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m},
2047 {"cfrshl32", 0xee000550, 8, ARM_CEXT_MAVERICK, do_mav_triple_4a},
2048 {"cfrshl64", 0xee000570, 8, ARM_CEXT_MAVERICK, do_mav_triple_4b},
2049 {"cfsh32", 0xee000500, 6, ARM_CEXT_MAVERICK, do_mav_shift_1},
2050 {"cfsh64", 0xee200500, 6, ARM_CEXT_MAVERICK, do_mav_shift_2},
2051 {"cfcmps", 0xee100490, 6, ARM_CEXT_MAVERICK, do_mav_triple_5a},
2052 {"cfcmpd", 0xee1004b0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5b},
2053 {"cfcmp32", 0xee100590, 7, ARM_CEXT_MAVERICK, do_mav_triple_5c},
2054 {"cfcmp64", 0xee1005b0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5d},
2055 {"cfabss", 0xee300400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
2056 {"cfabsd", 0xee300420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
2057 {"cfnegs", 0xee300440, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
2058 {"cfnegd", 0xee300460, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
2059 {"cfadds", 0xee300480, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
2060 {"cfaddd", 0xee3004a0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
2061 {"cfsubs", 0xee3004c0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
2062 {"cfsubd", 0xee3004e0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
2063 {"cfmuls", 0xee100400, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
2064 {"cfmuld", 0xee100420, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
2065 {"cfabs32", 0xee300500, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
2066 {"cfabs64", 0xee300520, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
2067 {"cfneg32", 0xee300540, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
2068 {"cfneg64", 0xee300560, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
2069 {"cfadd32", 0xee300580, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2070 {"cfadd64", 0xee3005a0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
2071 {"cfsub32", 0xee3005c0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2072 {"cfsub64", 0xee3005e0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
2073 {"cfmul32", 0xee100500, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2074 {"cfmul64", 0xee100520, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
2075 {"cfmac32", 0xee100540, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2076 {"cfmsc32", 0xee100560, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2077 {"cfmadd32", 0xee000600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
2078 {"cfmsub32", 0xee100600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
2079 {"cfmadda32", 0xee200600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
2080 {"cfmsuba32", 0xee300600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
b99bd4ef
NC
2081};
2082
2083/* Defines for various bits that we will want to toggle. */
2084#define INST_IMMEDIATE 0x02000000
2085#define OFFSET_REG 0x02000000
2086#define HWOFFSET_IMM 0x00400000
2087#define SHIFT_BY_REG 0x00000010
2088#define PRE_INDEX 0x01000000
2089#define INDEX_UP 0x00800000
2090#define WRITE_BACK 0x00200000
2091#define LDM_TYPE_2_OR_3 0x00400000
2092
2093#define LITERAL_MASK 0xf000f000
b99bd4ef 2094#define OPCODE_MASK 0xfe1fffff
90e4755a
RE
2095#define V4_STR_BIT 0x00000020
2096
b99bd4ef
NC
2097#define DATA_OP_SHIFT 21
2098
2099/* Codes to distinguish the arithmetic instructions. */
2100#define OPCODE_AND 0
2101#define OPCODE_EOR 1
2102#define OPCODE_SUB 2
2103#define OPCODE_RSB 3
2104#define OPCODE_ADD 4
2105#define OPCODE_ADC 5
2106#define OPCODE_SBC 6
2107#define OPCODE_RSC 7
2108#define OPCODE_TST 8
2109#define OPCODE_TEQ 9
2110#define OPCODE_CMP 10
2111#define OPCODE_CMN 11
2112#define OPCODE_ORR 12
2113#define OPCODE_MOV 13
2114#define OPCODE_BIC 14
2115#define OPCODE_MVN 15
2116
c9b604bd 2117/* Thumb v1 (ARMv4T). */
b99bd4ef
NC
2118static void do_t_nop PARAMS ((char *));
2119static void do_t_arit PARAMS ((char *));
2120static void do_t_add PARAMS ((char *));
2121static void do_t_asr PARAMS ((char *));
2122static void do_t_branch9 PARAMS ((char *));
2123static void do_t_branch12 PARAMS ((char *));
2124static void do_t_branch23 PARAMS ((char *));
2125static void do_t_bx PARAMS ((char *));
2126static void do_t_compare PARAMS ((char *));
2127static void do_t_ldmstm PARAMS ((char *));
2128static void do_t_ldr PARAMS ((char *));
2129static void do_t_ldrb PARAMS ((char *));
2130static void do_t_ldrh PARAMS ((char *));
2131static void do_t_lds PARAMS ((char *));
2132static void do_t_lsl PARAMS ((char *));
2133static void do_t_lsr PARAMS ((char *));
2134static void do_t_mov PARAMS ((char *));
2135static void do_t_push_pop PARAMS ((char *));
2136static void do_t_str PARAMS ((char *));
2137static void do_t_strb PARAMS ((char *));
2138static void do_t_strh PARAMS ((char *));
2139static void do_t_sub PARAMS ((char *));
2140static void do_t_swi PARAMS ((char *));
2141static void do_t_adr PARAMS ((char *));
2142
c9b604bd
RE
2143/* Thumb v2 (ARMv5T). */
2144static void do_t_blx PARAMS ((char *));
2145static void do_t_bkpt PARAMS ((char *));
2146
b99bd4ef
NC
2147#define T_OPCODE_MUL 0x4340
2148#define T_OPCODE_TST 0x4200
2149#define T_OPCODE_CMN 0x42c0
2150#define T_OPCODE_NEG 0x4240
2151#define T_OPCODE_MVN 0x43c0
2152
2153#define T_OPCODE_ADD_R3 0x1800
2154#define T_OPCODE_SUB_R3 0x1a00
2155#define T_OPCODE_ADD_HI 0x4400
2156#define T_OPCODE_ADD_ST 0xb000
2157#define T_OPCODE_SUB_ST 0xb080
2158#define T_OPCODE_ADD_SP 0xa800
2159#define T_OPCODE_ADD_PC 0xa000
2160#define T_OPCODE_ADD_I8 0x3000
2161#define T_OPCODE_SUB_I8 0x3800
2162#define T_OPCODE_ADD_I3 0x1c00
2163#define T_OPCODE_SUB_I3 0x1e00
2164
2165#define T_OPCODE_ASR_R 0x4100
2166#define T_OPCODE_LSL_R 0x4080
2167#define T_OPCODE_LSR_R 0x40c0
2168#define T_OPCODE_ASR_I 0x1000
2169#define T_OPCODE_LSL_I 0x0000
2170#define T_OPCODE_LSR_I 0x0800
2171
2172#define T_OPCODE_MOV_I8 0x2000
2173#define T_OPCODE_CMP_I8 0x2800
2174#define T_OPCODE_CMP_LR 0x4280
2175#define T_OPCODE_MOV_HR 0x4600
2176#define T_OPCODE_CMP_HR 0x4500
2177
2178#define T_OPCODE_LDR_PC 0x4800
2179#define T_OPCODE_LDR_SP 0x9800
2180#define T_OPCODE_STR_SP 0x9000
2181#define T_OPCODE_LDR_IW 0x6800
2182#define T_OPCODE_STR_IW 0x6000
2183#define T_OPCODE_LDR_IH 0x8800
2184#define T_OPCODE_STR_IH 0x8000
2185#define T_OPCODE_LDR_IB 0x7800
2186#define T_OPCODE_STR_IB 0x7000
2187#define T_OPCODE_LDR_RW 0x5800
2188#define T_OPCODE_STR_RW 0x5000
2189#define T_OPCODE_LDR_RH 0x5a00
2190#define T_OPCODE_STR_RH 0x5200
2191#define T_OPCODE_LDR_RB 0x5c00
2192#define T_OPCODE_STR_RB 0x5400
2193
2194#define T_OPCODE_PUSH 0xb400
2195#define T_OPCODE_POP 0xbc00
2196
2197#define T_OPCODE_BRANCH 0xe7fe
2198
2199static int thumb_reg PARAMS ((char ** str, int hi_lo));
2200
2201#define THUMB_SIZE 2 /* Size of thumb instruction. */
2202#define THUMB_REG_LO 0x1
2203#define THUMB_REG_HI 0x2
2204#define THUMB_REG_ANY 0x3
2205
2206#define THUMB_H1 0x0080
2207#define THUMB_H2 0x0040
2208
2209#define THUMB_ASR 0
2210#define THUMB_LSL 1
2211#define THUMB_LSR 2
2212
2213#define THUMB_MOVE 0
2214#define THUMB_COMPARE 1
2215
2216#define THUMB_LOAD 0
2217#define THUMB_STORE 1
2218
2219#define THUMB_PP_PC_LR 0x0100
2220
2221/* These three are used for immediate shifts, do not alter. */
2222#define THUMB_WORD 2
2223#define THUMB_HALFWORD 1
2224#define THUMB_BYTE 0
2225
2226struct thumb_opcode
2227{
2228 /* Basic string to match. */
05d2d07e 2229 const char * template;
b99bd4ef
NC
2230
2231 /* Basic instruction code. */
2232 unsigned long value;
2233
2234 int size;
2235
2236 /* Which CPU variants this exists for. */
90e4755a 2237 unsigned long variant;
b99bd4ef
NC
2238
2239 /* Function to call to parse args. */
2240 void (* parms) PARAMS ((char *));
2241};
2242
05d2d07e 2243static const struct thumb_opcode tinsns[] =
b99bd4ef 2244{
c9b604bd 2245 /* Thumb v1 (ARMv4T). */
b89dddec
RE
2246 {"adc", 0x4140, 2, ARM_EXT_V4T, do_t_arit},
2247 {"add", 0x0000, 2, ARM_EXT_V4T, do_t_add},
2248 {"and", 0x4000, 2, ARM_EXT_V4T, do_t_arit},
2249 {"asr", 0x0000, 2, ARM_EXT_V4T, do_t_asr},
2250 {"b", T_OPCODE_BRANCH, 2, ARM_EXT_V4T, do_t_branch12},
2251 {"beq", 0xd0fe, 2, ARM_EXT_V4T, do_t_branch9},
2252 {"bne", 0xd1fe, 2, ARM_EXT_V4T, do_t_branch9},
2253 {"bcs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
2254 {"bhs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
2255 {"bcc", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
2256 {"bul", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
2257 {"blo", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
2258 {"bmi", 0xd4fe, 2, ARM_EXT_V4T, do_t_branch9},
2259 {"bpl", 0xd5fe, 2, ARM_EXT_V4T, do_t_branch9},
2260 {"bvs", 0xd6fe, 2, ARM_EXT_V4T, do_t_branch9},
2261 {"bvc", 0xd7fe, 2, ARM_EXT_V4T, do_t_branch9},
2262 {"bhi", 0xd8fe, 2, ARM_EXT_V4T, do_t_branch9},
2263 {"bls", 0xd9fe, 2, ARM_EXT_V4T, do_t_branch9},
2264 {"bge", 0xdafe, 2, ARM_EXT_V4T, do_t_branch9},
2265 {"blt", 0xdbfe, 2, ARM_EXT_V4T, do_t_branch9},
2266 {"bgt", 0xdcfe, 2, ARM_EXT_V4T, do_t_branch9},
2267 {"ble", 0xddfe, 2, ARM_EXT_V4T, do_t_branch9},
2268 {"bal", 0xdefe, 2, ARM_EXT_V4T, do_t_branch9},
2269 {"bic", 0x4380, 2, ARM_EXT_V4T, do_t_arit},
2270 {"bl", 0xf7fffffe, 4, ARM_EXT_V4T, do_t_branch23},
b89dddec
RE
2271 {"bx", 0x4700, 2, ARM_EXT_V4T, do_t_bx},
2272 {"cmn", T_OPCODE_CMN, 2, ARM_EXT_V4T, do_t_arit},
2273 {"cmp", 0x0000, 2, ARM_EXT_V4T, do_t_compare},
2274 {"eor", 0x4040, 2, ARM_EXT_V4T, do_t_arit},
2275 {"ldmia", 0xc800, 2, ARM_EXT_V4T, do_t_ldmstm},
2276 {"ldr", 0x0000, 2, ARM_EXT_V4T, do_t_ldr},
2277 {"ldrb", 0x0000, 2, ARM_EXT_V4T, do_t_ldrb},
2278 {"ldrh", 0x0000, 2, ARM_EXT_V4T, do_t_ldrh},
2279 {"ldrsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
2280 {"ldrsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
2281 {"ldsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
2282 {"ldsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
2283 {"lsl", 0x0000, 2, ARM_EXT_V4T, do_t_lsl},
2284 {"lsr", 0x0000, 2, ARM_EXT_V4T, do_t_lsr},
2285 {"mov", 0x0000, 2, ARM_EXT_V4T, do_t_mov},
2286 {"mul", T_OPCODE_MUL, 2, ARM_EXT_V4T, do_t_arit},
2287 {"mvn", T_OPCODE_MVN, 2, ARM_EXT_V4T, do_t_arit},
2288 {"neg", T_OPCODE_NEG, 2, ARM_EXT_V4T, do_t_arit},
2289 {"orr", 0x4300, 2, ARM_EXT_V4T, do_t_arit},
2290 {"pop", 0xbc00, 2, ARM_EXT_V4T, do_t_push_pop},
2291 {"push", 0xb400, 2, ARM_EXT_V4T, do_t_push_pop},
2292 {"ror", 0x41c0, 2, ARM_EXT_V4T, do_t_arit},
2293 {"sbc", 0x4180, 2, ARM_EXT_V4T, do_t_arit},
2294 {"stmia", 0xc000, 2, ARM_EXT_V4T, do_t_ldmstm},
2295 {"str", 0x0000, 2, ARM_EXT_V4T, do_t_str},
2296 {"strb", 0x0000, 2, ARM_EXT_V4T, do_t_strb},
2297 {"strh", 0x0000, 2, ARM_EXT_V4T, do_t_strh},
2298 {"swi", 0xdf00, 2, ARM_EXT_V4T, do_t_swi},
2299 {"sub", 0x0000, 2, ARM_EXT_V4T, do_t_sub},
2300 {"tst", T_OPCODE_TST, 2, ARM_EXT_V4T, do_t_arit},
b99bd4ef 2301 /* Pseudo ops: */
b89dddec
RE
2302 {"adr", 0x0000, 2, ARM_EXT_V4T, do_t_adr},
2303 {"nop", 0x46C0, 2, ARM_EXT_V4T, do_t_nop}, /* mov r8,r8 */
c9b604bd
RE
2304 /* Thumb v2 (ARMv5T). */
2305 {"blx", 0, 0, ARM_EXT_V5T, do_t_blx},
2306 {"bkpt", 0xbe00, 2, ARM_EXT_V5T, do_t_bkpt},
b99bd4ef
NC
2307};
2308
f03698e6 2309#define BAD_ARGS _("bad arguments to instruction")
b99bd4ef 2310#define BAD_PC _("r15 not allowed here")
f03698e6 2311#define BAD_COND _("instruction is not conditional")
b99bd4ef
NC
2312#define ERR_NO_ACCUM _("acc0 expected")
2313
2314static struct hash_control * arm_ops_hsh = NULL;
2315static struct hash_control * arm_tops_hsh = NULL;
2316static struct hash_control * arm_cond_hsh = NULL;
2317static struct hash_control * arm_shift_hsh = NULL;
b99bd4ef
NC
2318static struct hash_control * arm_psr_hsh = NULL;
2319
2320/* This table describes all the machine specific pseudo-ops the assembler
2321 has to support. The fields are:
2322 pseudo-op name without dot
2323 function to call to execute this pseudo-op
2324 Integer arg to pass to the function. */
2325
2326static void s_req PARAMS ((int));
2327static void s_align PARAMS ((int));
2328static void s_bss PARAMS ((int));
2329static void s_even PARAMS ((int));
2330static void s_ltorg PARAMS ((int));
2331static void s_arm PARAMS ((int));
2332static void s_thumb PARAMS ((int));
2333static void s_code PARAMS ((int));
2334static void s_force_thumb PARAMS ((int));
2335static void s_thumb_func PARAMS ((int));
2336static void s_thumb_set PARAMS ((int));
76feaaf3 2337#ifdef OBJ_ELF
b99bd4ef
NC
2338static void s_arm_elf_cons PARAMS ((int));
2339#endif
2340
2341static int my_get_expression PARAMS ((expressionS *, char **));
2342
05d2d07e 2343const pseudo_typeS md_pseudo_table[] =
b99bd4ef
NC
2344{
2345 /* Never called becasue '.req' does not start line. */
2346 { "req", s_req, 0 },
2347 { "bss", s_bss, 0 },
2348 { "align", s_align, 0 },
2349 { "arm", s_arm, 0 },
2350 { "thumb", s_thumb, 0 },
2351 { "code", s_code, 0 },
2352 { "force_thumb", s_force_thumb, 0 },
2353 { "thumb_func", s_thumb_func, 0 },
2354 { "thumb_set", s_thumb_set, 0 },
2355 { "even", s_even, 0 },
2356 { "ltorg", s_ltorg, 0 },
2357 { "pool", s_ltorg, 0 },
76feaaf3 2358#ifdef OBJ_ELF
b99bd4ef
NC
2359 { "word", s_arm_elf_cons, 4 },
2360 { "long", s_arm_elf_cons, 4 },
b99bd4ef
NC
2361#else
2362 { "word", cons, 4},
2363#endif
2364 { "extend", float_cons, 'x' },
2365 { "ldouble", float_cons, 'x' },
2366 { "packed", float_cons, 'p' },
2367 { 0, 0, 0 }
2368};
2369
03b1477f
RE
2370/* Other internal functions. */
2371static int arm_parse_extension PARAMS ((char *, int *));
2372static int arm_parse_cpu PARAMS ((char *));
2373static int arm_parse_arch PARAMS ((char *));
2374static int arm_parse_fpu PARAMS ((char *));
5a6c6817
NC
2375#if defined OBJ_COFF || defined OBJ_ELF
2376static void arm_add_note PARAMS ((const char *, const char *, unsigned int));
2377#endif
03b1477f 2378
b99bd4ef
NC
2379/* Stuff needed to resolve the label ambiguity
2380 As:
2381 ...
2382 label: <insn>
2383 may differ from:
2384 ...
2385 label:
2386 <insn>
2387*/
2388
2389symbolS * last_label_seen;
b34976b6 2390static int label_is_thumb_function_name = FALSE;
b99bd4ef 2391
3d0c9500 2392/* Literal Pool stuff. */
b99bd4ef
NC
2393
2394#define MAX_LITERAL_POOL_SIZE 1024
2395
3d0c9500
NC
2396/* Literal pool structure. Held on a per-section
2397 and per-sub-section basis. */
2398typedef struct literal_pool
b99bd4ef 2399{
3d0c9500
NC
2400 expressionS literals [MAX_LITERAL_POOL_SIZE];
2401 unsigned int next_free_entry;
2402 unsigned int id;
2403 symbolS * symbol;
2404 segT section;
2405 subsegT sub_section;
61b5f74b 2406 struct literal_pool * next;
3d0c9500 2407} literal_pool;
b99bd4ef 2408
3d0c9500
NC
2409/* Pointer to a linked list of literal pools. */
2410literal_pool * list_of_pools = NULL;
b99bd4ef 2411
3d0c9500
NC
2412static literal_pool * find_literal_pool PARAMS ((void));
2413static literal_pool * find_or_make_literal_pool PARAMS ((void));
b99bd4ef 2414
3d0c9500
NC
2415static literal_pool *
2416find_literal_pool ()
2417{
2418 literal_pool * pool;
2419
2420 for (pool = list_of_pools; pool != NULL; pool = pool->next)
2421 {
2422 if (pool->section == now_seg
2423 && pool->sub_section == now_subseg)
2424 break;
2425 }
2426
2427 return pool;
2428}
b99bd4ef 2429
3d0c9500
NC
2430static literal_pool *
2431find_or_make_literal_pool ()
2432{
2433 /* Next literal pool ID number. */
2434 static unsigned int latest_pool_num = 1;
2435 literal_pool * pool;
2436
2437 pool = find_literal_pool ();
b99bd4ef 2438
3d0c9500
NC
2439 if (pool == NULL)
2440 {
2441 /* Create a new pool. */
2442 pool = (literal_pool *) xmalloc (sizeof (* pool));
2443 if (! pool)
2444 return NULL;
2445
2446 pool->next_free_entry = 0;
2447 pool->section = now_seg;
2448 pool->sub_section = now_subseg;
2449 pool->next = list_of_pools;
2450 pool->symbol = NULL;
2451
2452 /* Add it to the list. */
2453 list_of_pools = pool;
2454 }
2455
2456 /* New pools, and emptied pools, will have a NULL symbol. */
2457 if (pool->symbol == NULL)
2458 {
2459 pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
2460 (valueT) 0, &zero_address_frag);
2461 pool->id = latest_pool_num ++;
2462 }
2463
2464 /* Done. */
2465 return pool;
2466}
2467
2468/* Add the literal in the global 'inst'
2469 structure to the relevent literal pool. */
b99bd4ef
NC
2470static int
2471add_to_lit_pool ()
2472{
61b5f74b 2473 literal_pool * pool;
3d0c9500 2474 unsigned int entry;
b99bd4ef 2475
3d0c9500 2476 pool = find_or_make_literal_pool ();
b99bd4ef 2477
3d0c9500
NC
2478 /* Check if this literal value is already in the pool. */
2479 for (entry = 0; entry < pool->next_free_entry; entry ++)
b99bd4ef 2480 {
3d0c9500
NC
2481 if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2482 && (inst.reloc.exp.X_op == O_constant)
2483 && (pool->literals[entry].X_add_number
b99bd4ef 2484 == inst.reloc.exp.X_add_number)
3d0c9500
NC
2485 && (pool->literals[entry].X_unsigned
2486 == inst.reloc.exp.X_unsigned))
b99bd4ef
NC
2487 break;
2488
3d0c9500
NC
2489 if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2490 && (inst.reloc.exp.X_op == O_symbol)
2491 && (pool->literals[entry].X_add_number
b99bd4ef 2492 == inst.reloc.exp.X_add_number)
3d0c9500 2493 && (pool->literals[entry].X_add_symbol
b99bd4ef 2494 == inst.reloc.exp.X_add_symbol)
3d0c9500 2495 && (pool->literals[entry].X_op_symbol
b99bd4ef 2496 == inst.reloc.exp.X_op_symbol))
3d0c9500 2497 break;
b99bd4ef
NC
2498 }
2499
3d0c9500
NC
2500 /* Do we need to create a new entry? */
2501 if (entry == pool->next_free_entry)
b99bd4ef 2502 {
3d0c9500 2503 if (entry >= MAX_LITERAL_POOL_SIZE)
b99bd4ef 2504 {
ed71e111 2505 inst.error = _("literal pool overflow");
b99bd4ef
NC
2506 return FAIL;
2507 }
2508
3d0c9500
NC
2509 pool->literals[entry] = inst.reloc.exp;
2510 pool->next_free_entry += 1;
b99bd4ef
NC
2511 }
2512
3d0c9500 2513 inst.reloc.exp.X_op = O_symbol;
08df2379 2514 inst.reloc.exp.X_add_number = ((int) entry) * 4 - 8;
3d0c9500 2515 inst.reloc.exp.X_add_symbol = pool->symbol;
b99bd4ef
NC
2516
2517 return SUCCESS;
2518}
2519
2520/* Can't use symbol_new here, so have to create a symbol and then at
2521 a later date assign it a value. Thats what these functions do. */
2522
2523static void
2524symbol_locate (symbolP, name, segment, valu, frag)
2525 symbolS * symbolP;
05d2d07e 2526 const char * name; /* It is copied, the caller can modify. */
b99bd4ef
NC
2527 segT segment; /* Segment identifier (SEG_<something>). */
2528 valueT valu; /* Symbol value. */
2529 fragS * frag; /* Associated fragment. */
2530{
2531 unsigned int name_length;
2532 char * preserved_copy_of_name;
2533
2534 name_length = strlen (name) + 1; /* +1 for \0. */
2535 obstack_grow (&notes, name, name_length);
2536 preserved_copy_of_name = obstack_finish (&notes);
2537#ifdef STRIP_UNDERSCORE
2538 if (preserved_copy_of_name[0] == '_')
2539 preserved_copy_of_name++;
2540#endif
2541
2542#ifdef tc_canonicalize_symbol_name
2543 preserved_copy_of_name =
2544 tc_canonicalize_symbol_name (preserved_copy_of_name);
2545#endif
2546
2547 S_SET_NAME (symbolP, preserved_copy_of_name);
2548
2549 S_SET_SEGMENT (symbolP, segment);
2550 S_SET_VALUE (symbolP, valu);
c62e1cc3 2551 symbol_clear_list_pointers (symbolP);
b99bd4ef
NC
2552
2553 symbol_set_frag (symbolP, frag);
2554
2555 /* Link to end of symbol chain. */
2556 {
2557 extern int symbol_table_frozen;
2558 if (symbol_table_frozen)
2559 abort ();
2560 }
2561
2562 symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
2563
2564 obj_symbol_new_hook (symbolP);
2565
2566#ifdef tc_symbol_new_hook
2567 tc_symbol_new_hook (symbolP);
2568#endif
2569
2570#ifdef DEBUG_SYMS
2571 verify_symbol_chain (symbol_rootP, symbol_lastP);
2572#endif /* DEBUG_SYMS */
2573}
2574
2575/* Check that an immediate is valid.
2576 If so, convert it to the right format. */
2577
2578static unsigned int
2579validate_immediate (val)
2580 unsigned int val;
2581{
2582 unsigned int a;
2583 unsigned int i;
2584
2585#define rotate_left(v, n) (v << n | v >> (32 - n))
2586
2587 for (i = 0; i < 32; i += 2)
2588 if ((a = rotate_left (val, i)) <= 0xff)
2589 return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */
2590
2591 return FAIL;
2592}
2593
2594/* Check to see if an immediate can be computed as two seperate immediate
2595 values, added together. We already know that this value cannot be
2596 computed by just one ARM instruction. */
2597
2598static unsigned int
2599validate_immediate_twopart (val, highpart)
2600 unsigned int val;
2601 unsigned int * highpart;
2602{
2603 unsigned int a;
2604 unsigned int i;
2605
2606 for (i = 0; i < 32; i += 2)
2607 if (((a = rotate_left (val, i)) & 0xff) != 0)
2608 {
2609 if (a & 0xff00)
2610 {
2611 if (a & ~ 0xffff)
2612 continue;
2613 * highpart = (a >> 8) | ((i + 24) << 7);
2614 }
2615 else if (a & 0xff0000)
2616 {
2617 if (a & 0xff000000)
2618 continue;
2619 * highpart = (a >> 16) | ((i + 16) << 7);
2620 }
2621 else
2622 {
2623 assert (a & 0xff000000);
2624 * highpart = (a >> 24) | ((i + 8) << 7);
2625 }
2626
2627 return (a & 0xff) | (i << 7);
2628 }
2629
2630 return FAIL;
2631}
2632
2633static int
2634validate_offset_imm (val, hwse)
2635 unsigned int val;
2636 int hwse;
2637{
2638 if ((hwse && val > 255) || val > 4095)
2639 return FAIL;
2640 return val;
2641}
2642
2643static void
2644s_req (a)
2645 int a ATTRIBUTE_UNUSED;
2646{
f03698e6 2647 as_bad (_("invalid syntax for .req directive"));
b99bd4ef
NC
2648}
2649
2650static void
2651s_bss (ignore)
2652 int ignore ATTRIBUTE_UNUSED;
2653{
2654 /* We don't support putting frags in the BSS segment, we fake it by
2655 marking in_bss, then looking at s_skip for clues. */
2656 subseg_set (bss_section, 0);
2657 demand_empty_rest_of_line ();
2658}
2659
2660static void
2661s_even (ignore)
2662 int ignore ATTRIBUTE_UNUSED;
2663{
2664 /* Never make frag if expect extra pass. */
2665 if (!need_pass_2)
2666 frag_align (1, 0, 0);
2667
2668 record_alignment (now_seg, 1);
2669
2670 demand_empty_rest_of_line ();
2671}
2672
2673static void
2674s_ltorg (ignored)
2675 int ignored ATTRIBUTE_UNUSED;
2676{
3d0c9500
NC
2677 unsigned int entry;
2678 literal_pool * pool;
b99bd4ef
NC
2679 char sym_name[20];
2680
3d0c9500
NC
2681 pool = find_literal_pool ();
2682 if (pool == NULL
2683 || pool->symbol == NULL
2684 || pool->next_free_entry == 0)
b99bd4ef
NC
2685 return;
2686
2687 /* Align pool as you have word accesses.
2688 Only make a frag if we have to. */
2689 if (!need_pass_2)
2690 frag_align (2, 0, 0);
2691
2692 record_alignment (now_seg, 2);
2693
3d0c9500 2694 sprintf (sym_name, "$$lit_\002%x", pool->id);
b99bd4ef 2695
3d0c9500 2696 symbol_locate (pool->symbol, sym_name, now_seg,
b99bd4ef 2697 (valueT) frag_now_fix (), frag_now);
3d0c9500 2698 symbol_table_insert (pool->symbol);
b99bd4ef 2699
3d0c9500 2700 ARM_SET_THUMB (pool->symbol, thumb_mode);
b99bd4ef
NC
2701
2702#if defined OBJ_COFF || defined OBJ_ELF
3d0c9500 2703 ARM_SET_INTERWORK (pool->symbol, support_interwork);
b99bd4ef
NC
2704#endif
2705
3d0c9500 2706 for (entry = 0; entry < pool->next_free_entry; entry ++)
b99bd4ef 2707 /* First output the expression in the instruction to the pool. */
3d0c9500 2708 emit_expr (&(pool->literals[entry]), 4); /* .word */
b99bd4ef 2709
3d0c9500
NC
2710 /* Mark the pool as empty. */
2711 pool->next_free_entry = 0;
2712 pool->symbol = NULL;
b99bd4ef
NC
2713}
2714
2715/* Same as s_align_ptwo but align 0 => align 2. */
2716
2717static void
2718s_align (unused)
2719 int unused ATTRIBUTE_UNUSED;
2720{
2721 register int temp;
2722 register long temp_fill;
2723 long max_alignment = 15;
2724
2725 temp = get_absolute_expression ();
2726 if (temp > max_alignment)
f03698e6 2727 as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
b99bd4ef
NC
2728 else if (temp < 0)
2729 {
f03698e6 2730 as_bad (_("alignment negative. 0 assumed."));
b99bd4ef
NC
2731 temp = 0;
2732 }
2733
2734 if (*input_line_pointer == ',')
2735 {
2736 input_line_pointer++;
2737 temp_fill = get_absolute_expression ();
2738 }
2739 else
2740 temp_fill = 0;
2741
2742 if (!temp)
2743 temp = 2;
2744
2745 /* Only make a frag if we HAVE to. */
2746 if (temp && !need_pass_2)
2747 frag_align (temp, (int) temp_fill, 0);
2748 demand_empty_rest_of_line ();
2749
2750 record_alignment (now_seg, temp);
2751}
2752
2753static void
2754s_force_thumb (ignore)
2755 int ignore ATTRIBUTE_UNUSED;
2756{
2757 /* If we are not already in thumb mode go into it, EVEN if
2758 the target processor does not support thumb instructions.
2759 This is used by gcc/config/arm/lib1funcs.asm for example
2760 to compile interworking support functions even if the
2761 target processor should not support interworking. */
2762 if (! thumb_mode)
2763 {
2764 thumb_mode = 2;
2765
2766 record_alignment (now_seg, 1);
2767 }
2768
2769 demand_empty_rest_of_line ();
2770}
2771
2772static void
2773s_thumb_func (ignore)
2774 int ignore ATTRIBUTE_UNUSED;
2775{
2776 if (! thumb_mode)
2777 opcode_select (16);
2778
2779 /* The following label is the name/address of the start of a Thumb function.
2780 We need to know this for the interworking support. */
b34976b6 2781 label_is_thumb_function_name = TRUE;
b99bd4ef
NC
2782
2783 demand_empty_rest_of_line ();
2784}
2785
2786/* Perform a .set directive, but also mark the alias as
2787 being a thumb function. */
2788
2789static void
2790s_thumb_set (equiv)
2791 int equiv;
2792{
2793 /* XXX the following is a duplicate of the code for s_set() in read.c
2794 We cannot just call that code as we need to get at the symbol that
2795 is created. */
2796 register char * name;
2797 register char delim;
2798 register char * end_name;
2799 register symbolS * symbolP;
2800
2801 /* Especial apologies for the random logic:
2802 This just grew, and could be parsed much more simply!
2803 Dean - in haste. */
2804 name = input_line_pointer;
2805 delim = get_symbol_end ();
2806 end_name = input_line_pointer;
2807 *end_name = delim;
2808
2809 SKIP_WHITESPACE ();
2810
2811 if (*input_line_pointer != ',')
2812 {
2813 *end_name = 0;
f03698e6 2814 as_bad (_("expected comma after name \"%s\""), name);
b99bd4ef
NC
2815 *end_name = delim;
2816 ignore_rest_of_line ();
2817 return;
2818 }
2819
2820 input_line_pointer++;
2821 *end_name = 0;
2822
2823 if (name[0] == '.' && name[1] == '\0')
2824 {
2825 /* XXX - this should not happen to .thumb_set. */
2826 abort ();
2827 }
2828
2829 if ((symbolP = symbol_find (name)) == NULL
2830 && (symbolP = md_undefined_symbol (name)) == NULL)
2831 {
2832#ifndef NO_LISTING
2833 /* When doing symbol listings, play games with dummy fragments living
2834 outside the normal fragment chain to record the file and line info
2835 for this symbol. */
2836 if (listing & LISTING_SYMBOLS)
2837 {
2838 extern struct list_info_struct * listing_tail;
2839 fragS * dummy_frag = (fragS *) xmalloc (sizeof (fragS));
2840
2841 memset (dummy_frag, 0, sizeof (fragS));
2842 dummy_frag->fr_type = rs_fill;
2843 dummy_frag->line = listing_tail;
2844 symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
2845 dummy_frag->fr_symbol = symbolP;
2846 }
2847 else
2848#endif
2849 symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
2850
2851#ifdef OBJ_COFF
2852 /* "set" symbols are local unless otherwise specified. */
2853 SF_SET_LOCAL (symbolP);
2854#endif /* OBJ_COFF */
2855 } /* Make a new symbol. */
2856
2857 symbol_table_insert (symbolP);
2858
2859 * end_name = delim;
2860
2861 if (equiv
2862 && S_IS_DEFINED (symbolP)
2863 && S_GET_SEGMENT (symbolP) != reg_section)
2864 as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
2865
2866 pseudo_set (symbolP);
2867
2868 demand_empty_rest_of_line ();
2869
2870 /* XXX Now we come to the Thumb specific bit of code. */
2871
2872 THUMB_SET_FUNC (symbolP, 1);
2873 ARM_SET_THUMB (symbolP, 1);
2874#if defined OBJ_ELF || defined OBJ_COFF
2875 ARM_SET_INTERWORK (symbolP, support_interwork);
2876#endif
2877}
2878
b99bd4ef
NC
2879static void
2880opcode_select (width)
2881 int width;
2882{
2883 switch (width)
2884 {
2885 case 16:
2886 if (! thumb_mode)
2887 {
b89dddec 2888 if (! (cpu_variant & ARM_EXT_V4T))
b99bd4ef
NC
2889 as_bad (_("selected processor does not support THUMB opcodes"));
2890
2891 thumb_mode = 1;
2892 /* No need to force the alignment, since we will have been
2893 coming from ARM mode, which is word-aligned. */
2894 record_alignment (now_seg, 1);
2895 }
2896 break;
2897
2898 case 32:
2899 if (thumb_mode)
2900 {
03b1477f 2901 if ((cpu_variant & ARM_ALL) == ARM_EXT_V4T)
b99bd4ef
NC
2902 as_bad (_("selected processor does not support ARM opcodes"));
2903
2904 thumb_mode = 0;
2905
2906 if (!need_pass_2)
cc8a6dd0 2907 frag_align (2, 0, 0);
b99bd4ef 2908
cc8a6dd0 2909 record_alignment (now_seg, 1);
b99bd4ef
NC
2910 }
2911 break;
2912
2913 default:
2914 as_bad (_("invalid instruction size selected (%d)"), width);
2915 }
2916}
2917
2918static void
2919s_arm (ignore)
2920 int ignore ATTRIBUTE_UNUSED;
2921{
2922 opcode_select (32);
2923 demand_empty_rest_of_line ();
2924}
2925
2926static void
2927s_thumb (ignore)
2928 int ignore ATTRIBUTE_UNUSED;
2929{
2930 opcode_select (16);
2931 demand_empty_rest_of_line ();
2932}
2933
2934static void
2935s_code (unused)
2936 int unused ATTRIBUTE_UNUSED;
2937{
2938 register int temp;
2939
2940 temp = get_absolute_expression ();
2941 switch (temp)
2942 {
2943 case 16:
2944 case 32:
2945 opcode_select (temp);
2946 break;
2947
2948 default:
2949 as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
2950 }
2951}
2952
2953static void
2954end_of_line (str)
f03698e6 2955 char *str;
b99bd4ef
NC
2956{
2957 skip_whitespace (str);
2958
f03698e6
RE
2959 if (*str != '\0' && !inst.error)
2960 inst.error = _("garbage following instruction");
b99bd4ef
NC
2961}
2962
2963static int
2964skip_past_comma (str)
2965 char ** str;
2966{
2967 char * p = * str, c;
2968 int comma = 0;
2969
2970 while ((c = *p) == ' ' || c == ',')
2971 {
2972 p++;
2973 if (c == ',' && comma++)
2974 return FAIL;
2975 }
2976
2977 if (c == '\0')
2978 return FAIL;
2979
2980 *str = p;
2981 return comma ? SUCCESS : FAIL;
2982}
2983
2984/* A standard register must be given at this point.
2985 SHIFT is the place to put it in inst.instruction.
2986 Restores input start point on error.
2987 Returns the reg#, or FAIL. */
2988
2989static int
2990reg_required_here (str, shift)
2991 char ** str;
2992 int shift;
2993{
2994 static char buff [128]; /* XXX */
2995 int reg;
2996 char * start = * str;
2997
6c43fab6 2998 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL)
b99bd4ef
NC
2999 {
3000 if (shift >= 0)
3001 inst.instruction |= reg << shift;
3002 return reg;
3003 }
3004
3005 /* Restore the start point, we may have got a reg of the wrong class. */
3006 *str = start;
3007
3008 /* In the few cases where we might be able to accept something else
3009 this error can be overridden. */
f03698e6 3010 sprintf (buff, _("register expected, not '%.100s'"), start);
b99bd4ef
NC
3011 inst.error = buff;
3012
3013 return FAIL;
3014}
3015
5a6c6817 3016/* A Intel Wireless MMX technology register
e16bb312
NC
3017 must be given at this point.
3018 Shift is the place to put it in inst.instruction.
3019 Restores input start point on err.
3020 Returns the reg#, or FAIL. */
3021
3022static int
3023wreg_required_here (str, shift, reg_type)
3024 char ** str;
3025 int shift;
3026 enum wreg_type reg_type;
3027{
3028 static char buff [128];
3029 int reg;
3030 char * start = *str;
3031
3032 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_IWMMXT].htab)) != FAIL)
3033 {
3034 if (wr_register (reg)
3035 && (reg_type == IWMMXT_REG_WR || reg_type == IWMMXT_REG_WR_OR_WC))
3036 {
3037 if (shift >= 0)
3038 inst.instruction |= (reg ^ WR_PREFIX) << shift;
3039 return reg;
3040 }
3041 else if (wc_register (reg)
3042 && (reg_type == IWMMXT_REG_WC || reg_type == IWMMXT_REG_WR_OR_WC))
3043 {
3044 if (shift >= 0)
3045 inst.instruction |= (reg ^ WC_PREFIX) << shift;
3046 return reg;
3047 }
3048 else if ((wcg_register (reg) && reg_type == IWMMXT_REG_WCG))
3049 {
3050 if (shift >= 0)
3051 inst.instruction |= ((reg ^ WC_PREFIX) - 8) << shift;
3052 return reg;
3053 }
3054 }
3055
3056 /* Restore the start point, we may have got a reg of the wrong class. */
3057 *str = start;
3058
3059 /* In the few cases where we might be able to accept
3060 something else this error can be overridden. */
5a6c6817 3061 sprintf (buff, _("Intel Wireless MMX technology register expected, not '%.100s'"), start);
e16bb312
NC
3062 inst.error = buff;
3063
3064 return FAIL;
3065}
3066
05d2d07e 3067static const struct asm_psr *
b99bd4ef
NC
3068arm_psr_parse (ccp)
3069 register char ** ccp;
3070{
3071 char * start = * ccp;
3072 char c;
3073 char * p;
05d2d07e 3074 const struct asm_psr * psr;
b99bd4ef
NC
3075
3076 p = start;
3077
3078 /* Skip to the end of the next word in the input stream. */
3079 do
3080 {
3081 c = *p++;
3082 }
3882b010 3083 while (ISALPHA (c) || c == '_');
b99bd4ef
NC
3084
3085 /* Terminate the word. */
3086 *--p = 0;
3087
3088 /* CPSR's and SPSR's can now be lowercase. This is just a convenience
3089 feature for ease of use and backwards compatibility. */
3090 if (!strncmp (start, "cpsr", 4))
3091 strncpy (start, "CPSR", 4);
3092 else if (!strncmp (start, "spsr", 4))
3093 strncpy (start, "SPSR", 4);
3094
3095 /* Now locate the word in the psr hash table. */
05d2d07e 3096 psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start);
b99bd4ef
NC
3097
3098 /* Restore the input stream. */
3099 *p = c;
3100
3101 /* If we found a valid match, advance the
3102 stream pointer past the end of the word. */
3103 *ccp = p;
3104
3105 return psr;
3106}
3107
3108/* Parse the input looking for a PSR flag. */
3109
3110static int
3111psr_required_here (str)
3112 char ** str;
3113{
3114 char * start = * str;
05d2d07e 3115 const struct asm_psr * psr;
b99bd4ef
NC
3116
3117 psr = arm_psr_parse (str);
3118
3119 if (psr)
3120 {
3121 /* If this is the SPSR that is being modified, set the R bit. */
3122 if (! psr->cpsr)
3123 inst.instruction |= SPSR_BIT;
3124
3125 /* Set the psr flags in the MSR instruction. */
3126 inst.instruction |= psr->field << PSR_SHIFT;
3127
3128 return SUCCESS;
3129 }
3130
3131 /* In the few cases where we might be able to accept
3132 something else this error can be overridden. */
3133 inst.error = _("flag for {c}psr instruction expected");
3134
3135 /* Restore the start point. */
3136 *str = start;
3137 return FAIL;
3138}
3139
3140static int
3141co_proc_number (str)
6c43fab6 3142 char **str;
b99bd4ef
NC
3143{
3144 int processor, pchar;
6c43fab6 3145 char *start;
b99bd4ef 3146
6c43fab6
RE
3147 skip_whitespace (*str);
3148 start = *str;
b99bd4ef
NC
3149
3150 /* The data sheet seems to imply that just a number on its own is valid
3151 here, but the RISC iX assembler seems to accept a prefix 'p'. We will
3152 accept either. */
6c43fab6
RE
3153 if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab))
3154 == FAIL)
b99bd4ef 3155 {
6c43fab6
RE
3156 *str = start;
3157
3158 pchar = *(*str)++;
3159 if (pchar >= '0' && pchar <= '9')
b99bd4ef 3160 {
6c43fab6
RE
3161 processor = pchar - '0';
3162 if (**str >= '0' && **str <= '9')
b99bd4ef 3163 {
6c43fab6
RE
3164 processor = processor * 10 + *(*str)++ - '0';
3165 if (processor > 15)
3166 {
f03698e6 3167 inst.error = _("illegal co-processor number");
6c43fab6
RE
3168 return FAIL;
3169 }
b99bd4ef
NC
3170 }
3171 }
6c43fab6
RE
3172 else
3173 {
f03698e6 3174 inst.error = _("bad or missing co-processor number");
6c43fab6
RE
3175 return FAIL;
3176 }
b99bd4ef
NC
3177 }
3178
3179 inst.instruction |= processor << 8;
3180 return SUCCESS;
3181}
3182
3183static int
3184cp_opc_expr (str, where, length)
3185 char ** str;
3186 int where;
3187 int length;
3188{
3189 expressionS expr;
3190
3191 skip_whitespace (* str);
3192
3193 memset (&expr, '\0', sizeof (expr));
3194
3195 if (my_get_expression (&expr, str))
3196 return FAIL;
3197 if (expr.X_op != O_constant)
3198 {
3199 inst.error = _("bad or missing expression");
3200 return FAIL;
3201 }
3202
3203 if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
3204 {
3205 inst.error = _("immediate co-processor expression too large");
3206 return FAIL;
3207 }
3208
3209 inst.instruction |= expr.X_add_number << where;
3210 return SUCCESS;
3211}
3212
3213static int
3214cp_reg_required_here (str, where)
3215 char ** str;
3216 int where;
3217{
3218 int reg;
3219 char * start = *str;
3220
6c43fab6 3221 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
b99bd4ef 3222 {
b99bd4ef
NC
3223 inst.instruction |= reg << where;
3224 return reg;
3225 }
3226
3227 /* In the few cases where we might be able to accept something else
3228 this error can be overridden. */
f03698e6 3229 inst.error = _("co-processor register expected");
b99bd4ef
NC
3230
3231 /* Restore the start point. */
3232 *str = start;
3233 return FAIL;
3234}
3235
3236static int
3237fp_reg_required_here (str, where)
3238 char ** str;
3239 int where;
3240{
3241 int reg;
3242 char * start = * str;
3243
6c43fab6 3244 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL)
b99bd4ef 3245 {
b99bd4ef
NC
3246 inst.instruction |= reg << where;
3247 return reg;
3248 }
3249
3250 /* In the few cases where we might be able to accept something else
3251 this error can be overridden. */
f03698e6 3252 inst.error = _("floating point register expected");
b99bd4ef
NC
3253
3254 /* Restore the start point. */
3255 *str = start;
3256 return FAIL;
3257}
3258
3259static int
3260cp_address_offset (str)
3261 char ** str;
3262{
3263 int offset;
3264
3265 skip_whitespace (* str);
3266
3267 if (! is_immediate_prefix (**str))
3268 {
3269 inst.error = _("immediate expression expected");
3270 return FAIL;
3271 }
3272
3273 (*str)++;
3274
3275 if (my_get_expression (& inst.reloc.exp, str))
3276 return FAIL;
3277
3278 if (inst.reloc.exp.X_op == O_constant)
3279 {
3280 offset = inst.reloc.exp.X_add_number;
3281
3282 if (offset & 3)
3283 {
3284 inst.error = _("co-processor address must be word aligned");
3285 return FAIL;
3286 }
3287
3288 if (offset > 1023 || offset < -1023)
3289 {
3290 inst.error = _("offset too large");
3291 return FAIL;
3292 }
3293
3294 if (offset >= 0)
3295 inst.instruction |= INDEX_UP;
3296 else
3297 offset = -offset;
3298
3299 inst.instruction |= offset >> 2;
3300 }
3301 else
3302 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
3303
3304 return SUCCESS;
3305}
3306
3307static int
bfae80f2 3308cp_address_required_here (str, wb_ok)
b99bd4ef 3309 char ** str;
bfae80f2 3310 int wb_ok;
b99bd4ef
NC
3311{
3312 char * p = * str;
3313 int pre_inc = 0;
3314 int write_back = 0;
3315
3316 if (*p == '[')
3317 {
3318 int reg;
3319
3320 p++;
3321 skip_whitespace (p);
3322
3323 if ((reg = reg_required_here (& p, 16)) == FAIL)
3324 return FAIL;
3325
3326 skip_whitespace (p);
3327
3328 if (*p == ']')
3329 {
3330 p++;
3331
f02232aa
NC
3332 skip_whitespace (p);
3333
3334 if (*p == '\0')
b99bd4ef 3335 {
f02232aa
NC
3336 /* As an extension to the official ARM syntax we allow:
3337
3338 [Rn]
3339
3340 as a short hand for:
3341
3342 [Rn,#0] */
3343 inst.instruction |= PRE_INDEX | INDEX_UP;
3344 *str = p;
3345 return SUCCESS;
3346 }
3347
3348 if (skip_past_comma (& p) == FAIL)
3349 {
3350 inst.error = _("comma expected after closing square bracket");
3351 return FAIL;
3352 }
b99bd4ef 3353
f02232aa
NC
3354 skip_whitespace (p);
3355
3356 if (*p == '#')
3357 {
3358 if (wb_ok)
b99bd4ef 3359 {
f02232aa
NC
3360 /* [Rn], #expr */
3361 write_back = WRITE_BACK;
3362
3363 if (reg == REG_PC)
3364 {
3365 inst.error = _("pc may not be used in post-increment");
3366 return FAIL;
3367 }
3368
3369 if (cp_address_offset (& p) == FAIL)
3370 return FAIL;
b99bd4ef 3371 }
f02232aa
NC
3372 else
3373 pre_inc = PRE_INDEX | INDEX_UP;
3374 }
3375 else if (*p == '{')
3376 {
3377 int option;
b99bd4ef 3378
f02232aa
NC
3379 /* [Rn], {<expr>} */
3380 p++;
3381
3382 skip_whitespace (p);
3383
3384 if (my_get_expression (& inst.reloc.exp, & p))
b99bd4ef 3385 return FAIL;
f02232aa
NC
3386
3387 if (inst.reloc.exp.X_op == O_constant)
3388 {
3389 option = inst.reloc.exp.X_add_number;
3390
3391 if (option > 255 || option < 0)
3392 {
3393 inst.error = _("'option' field too large");
3394 return FAIL;
3395 }
3396
3397 skip_whitespace (p);
3398
3399 if (*p != '}')
3400 {
3401 inst.error = _("'}' expected at end of 'option' field");
3402 return FAIL;
3403 }
3404 else
3405 {
3406 p++;
3407 inst.instruction |= option;
3408 inst.instruction |= INDEX_UP;
3409 }
3410 }
3411 else
3412 {
3413 inst.error = _("non-constant expressions for 'option' field not supported");
3414 return FAIL;
3415 }
b99bd4ef
NC
3416 }
3417 else
f02232aa
NC
3418 {
3419 inst.error = _("# or { expected after comma");
3420 return FAIL;
3421 }
b99bd4ef
NC
3422 }
3423 else
3424 {
3425 /* '['Rn, #expr']'[!] */
3426
3427 if (skip_past_comma (& p) == FAIL)
3428 {
3429 inst.error = _("pre-indexed expression expected");
3430 return FAIL;
3431 }
3432
3433 pre_inc = PRE_INDEX;
3434
3435 if (cp_address_offset (& p) == FAIL)
3436 return FAIL;
3437
3438 skip_whitespace (p);
3439
3440 if (*p++ != ']')
3441 {
3442 inst.error = _("missing ]");
3443 return FAIL;
3444 }
3445
3446 skip_whitespace (p);
3447
bfae80f2 3448 if (wb_ok && *p == '!')
b99bd4ef
NC
3449 {
3450 if (reg == REG_PC)
3451 {
3452 inst.error = _("pc may not be used with write-back");
3453 return FAIL;
3454 }
3455
3456 p++;
3457 write_back = WRITE_BACK;
3458 }
3459 }
3460 }
3461 else
3462 {
3463 if (my_get_expression (&inst.reloc.exp, &p))
3464 return FAIL;
3465
3466 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
3467 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
3468 inst.reloc.pc_rel = 1;
3469 inst.instruction |= (REG_PC << 16);
3470 pre_inc = PRE_INDEX;
3471 }
3472
3473 inst.instruction |= write_back | pre_inc;
3474 *str = p;
3475 return SUCCESS;
3476}
3477
e16bb312
NC
3478static int
3479cp_byte_address_offset (str)
3480 char ** str;
3481{
3482 int offset;
3483
3484 skip_whitespace (* str);
3485
3486 if (! is_immediate_prefix (**str))
3487 {
3488 inst.error = _("immediate expression expected");
3489 return FAIL;
3490 }
3491
3492 (*str)++;
3493
3494 if (my_get_expression (& inst.reloc.exp, str))
3495 return FAIL;
3496
3497 if (inst.reloc.exp.X_op == O_constant)
3498 {
3499 offset = inst.reloc.exp.X_add_number;
3500
3501 if (offset > 255 || offset < -255)
3502 {
3503 inst.error = _("offset too large");
3504 return FAIL;
3505 }
3506
3507 if (offset >= 0)
3508 inst.instruction |= INDEX_UP;
3509 else
3510 offset = -offset;
3511
3512 inst.instruction |= offset;
3513 }
3514 else
3515 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
3516
3517 return SUCCESS;
3518}
3519
3520static int
3521cp_byte_address_required_here (str)
3522 char ** str;
3523{
3524 char * p = * str;
3525 int pre_inc = 0;
3526 int write_back = 0;
3527
3528 if (*p == '[')
3529 {
3530 int reg;
3531
3532 p++;
3533 skip_whitespace (p);
3534
3535 if ((reg = reg_required_here (& p, 16)) == FAIL)
3536 return FAIL;
3537
3538 skip_whitespace (p);
3539
3540 if (*p == ']')
3541 {
3542 p++;
3543
3544 if (skip_past_comma (& p) == SUCCESS)
3545 {
3546 /* [Rn], #expr */
3547 write_back = WRITE_BACK;
3548
3549 if (reg == REG_PC)
3550 {
3551 inst.error = _("pc may not be used in post-increment");
3552 return FAIL;
3553 }
3554
3555 if (cp_byte_address_offset (& p) == FAIL)
3556 return FAIL;
3557 }
3558 else
3559 pre_inc = PRE_INDEX | INDEX_UP;
3560 }
3561 else
3562 {
3563 /* '['Rn, #expr']'[!] */
3564
3565 if (skip_past_comma (& p) == FAIL)
3566 {
3567 inst.error = _("pre-indexed expression expected");
3568 return FAIL;
3569 }
3570
3571 pre_inc = PRE_INDEX;
3572
3573 if (cp_byte_address_offset (& p) == FAIL)
3574 return FAIL;
3575
3576 skip_whitespace (p);
3577
3578 if (*p++ != ']')
3579 {
3580 inst.error = _("missing ]");
3581 return FAIL;
3582 }
3583
3584 skip_whitespace (p);
3585
3586 if (*p == '!')
3587 {
3588 if (reg == REG_PC)
3589 {
3590 inst.error = _("pc may not be used with write-back");
3591 return FAIL;
3592 }
3593
3594 p++;
3595 write_back = WRITE_BACK;
3596 }
3597 }
3598 }
3599 else
3600 {
3601 if (my_get_expression (&inst.reloc.exp, &p))
3602 return FAIL;
3603
3604 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
3605 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
3606 inst.reloc.pc_rel = 1;
3607 inst.instruction |= (REG_PC << 16);
3608 pre_inc = PRE_INDEX;
3609 }
3610
3611 inst.instruction |= write_back | pre_inc;
3612 *str = p;
3613 return SUCCESS;
3614}
3615
b99bd4ef 3616static void
f2b7cb0a 3617do_empty (str)
b99bd4ef 3618 char * str;
b99bd4ef
NC
3619{
3620 /* Do nothing really. */
b99bd4ef
NC
3621 end_of_line (str);
3622 return;
3623}
3624
3625static void
f2b7cb0a 3626do_mrs (str)
b99bd4ef 3627 char *str;
b99bd4ef
NC
3628{
3629 int skip = 0;
3630
3631 /* Only one syntax. */
3632 skip_whitespace (str);
3633
3634 if (reg_required_here (&str, 12) == FAIL)
3635 {
3636 inst.error = BAD_ARGS;
3637 return;
3638 }
3639
3640 if (skip_past_comma (&str) == FAIL)
3641 {
3642 inst.error = _("comma expected after register name");
3643 return;
3644 }
3645
3646 skip_whitespace (str);
3647
3648 if ( strcmp (str, "CPSR") == 0
3649 || strcmp (str, "SPSR") == 0
3650 /* Lower case versions for backwards compatability. */
3651 || strcmp (str, "cpsr") == 0
3652 || strcmp (str, "spsr") == 0)
3653 skip = 4;
3654
3655 /* This is for backwards compatability with older toolchains. */
3656 else if ( strcmp (str, "cpsr_all") == 0
3657 || strcmp (str, "spsr_all") == 0)
3658 skip = 8;
3659 else
3660 {
f03698e6 3661 inst.error = _("CPSR or SPSR expected");
b99bd4ef
NC
3662 return;
3663 }
3664
3665 if (* str == 's' || * str == 'S')
3666 inst.instruction |= SPSR_BIT;
3667 str += skip;
3668
b99bd4ef
NC
3669 end_of_line (str);
3670}
3671
3672/* Two possible forms:
3673 "{C|S}PSR_<field>, Rm",
3674 "{C|S}PSR_f, #expression". */
3675
3676static void
f2b7cb0a 3677do_msr (str)
b99bd4ef 3678 char * str;
b99bd4ef
NC
3679{
3680 skip_whitespace (str);
3681
3682 if (psr_required_here (& str) == FAIL)
3683 return;
3684
3685 if (skip_past_comma (& str) == FAIL)
3686 {
3687 inst.error = _("comma missing after psr flags");
3688 return;
3689 }
3690
3691 skip_whitespace (str);
3692
3693 if (reg_required_here (& str, 0) != FAIL)
3694 {
3695 inst.error = NULL;
b99bd4ef
NC
3696 end_of_line (str);
3697 return;
3698 }
3699
3700 if (! is_immediate_prefix (* str))
3701 {
3702 inst.error =
3703 _("only a register or immediate value can follow a psr flag");
3704 return;
3705 }
3706
3707 str ++;
3708 inst.error = NULL;
3709
3710 if (my_get_expression (& inst.reloc.exp, & str))
3711 {
3712 inst.error =
3713 _("only a register or immediate value can follow a psr flag");
3714 return;
3715 }
3716
3717#if 0 /* The first edition of the ARM architecture manual stated that
3718 writing anything other than the flags with an immediate operation
3719 had UNPREDICTABLE effects. This constraint was removed in the
3720 second edition of the specification. */
3721 if ((cpu_variant & ARM_EXT_V5) != ARM_EXT_V5
3722 && inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
3723 {
3724 inst.error = _("immediate value cannot be used to set this field");
3725 return;
3726 }
3727#endif
3728
f2b7cb0a 3729 inst.instruction |= INST_IMMEDIATE;
b99bd4ef
NC
3730
3731 if (inst.reloc.exp.X_add_symbol)
3732 {
3733 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
3734 inst.reloc.pc_rel = 0;
3735 }
3736 else
3737 {
3738 unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
3739
3740 if (value == (unsigned) FAIL)
3741 {
f03698e6 3742 inst.error = _("invalid constant");
b99bd4ef
NC
3743 return;
3744 }
3745
3746 inst.instruction |= value;
3747 }
3748
3749 inst.error = NULL;
b99bd4ef
NC
3750 end_of_line (str);
3751}
3752
3753/* Long Multiply Parser
3754 UMULL RdLo, RdHi, Rm, Rs
3755 SMULL RdLo, RdHi, Rm, Rs
3756 UMLAL RdLo, RdHi, Rm, Rs
3757 SMLAL RdLo, RdHi, Rm, Rs. */
3758
3759static void
f2b7cb0a 3760do_mull (str)
b99bd4ef 3761 char * str;
b99bd4ef
NC
3762{
3763 int rdlo, rdhi, rm, rs;
3764
3765 /* Only one format "rdlo, rdhi, rm, rs". */
3766 skip_whitespace (str);
3767
3768 if ((rdlo = reg_required_here (&str, 12)) == FAIL)
3769 {
3770 inst.error = BAD_ARGS;
3771 return;
3772 }
3773
3774 if (skip_past_comma (&str) == FAIL
3775 || (rdhi = reg_required_here (&str, 16)) == FAIL)
3776 {
3777 inst.error = BAD_ARGS;
3778 return;
3779 }
3780
3781 if (skip_past_comma (&str) == FAIL
3782 || (rm = reg_required_here (&str, 0)) == FAIL)
3783 {
3784 inst.error = BAD_ARGS;
3785 return;
3786 }
3787
3788 /* rdhi, rdlo and rm must all be different. */
3789 if (rdlo == rdhi || rdlo == rm || rdhi == rm)
3790 as_tsktsk (_("rdhi, rdlo and rm must all be different"));
3791
3792 if (skip_past_comma (&str) == FAIL
3793 || (rs = reg_required_here (&str, 8)) == FAIL)
3794 {
3795 inst.error = BAD_ARGS;
3796 return;
3797 }
3798
3799 if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
3800 {
3801 inst.error = BAD_PC;
3802 return;
3803 }
3804
b99bd4ef
NC
3805 end_of_line (str);
3806 return;
3807}
3808
3809static void
f2b7cb0a 3810do_mul (str)
b99bd4ef 3811 char * str;
b99bd4ef
NC
3812{
3813 int rd, rm;
3814
3815 /* Only one format "rd, rm, rs". */
3816 skip_whitespace (str);
3817
3818 if ((rd = reg_required_here (&str, 16)) == FAIL)
3819 {
3820 inst.error = BAD_ARGS;
3821 return;
3822 }
3823
3824 if (rd == REG_PC)
3825 {
3826 inst.error = BAD_PC;
3827 return;
3828 }
3829
3830 if (skip_past_comma (&str) == FAIL
3831 || (rm = reg_required_here (&str, 0)) == FAIL)
3832 {
3833 inst.error = BAD_ARGS;
3834 return;
3835 }
3836
3837 if (rm == REG_PC)
3838 {
3839 inst.error = BAD_PC;
3840 return;
3841 }
3842
3843 if (rm == rd)
3844 as_tsktsk (_("rd and rm should be different in mul"));
3845
3846 if (skip_past_comma (&str) == FAIL
3847 || (rm = reg_required_here (&str, 8)) == FAIL)
3848 {
3849 inst.error = BAD_ARGS;
3850 return;
3851 }
3852
3853 if (rm == REG_PC)
3854 {
3855 inst.error = BAD_PC;
3856 return;
3857 }
3858
b99bd4ef
NC
3859 end_of_line (str);
3860 return;
3861}
3862
3863static void
f2b7cb0a 3864do_mla (str)
b99bd4ef 3865 char * str;
b99bd4ef
NC
3866{
3867 int rd, rm;
3868
3869 /* Only one format "rd, rm, rs, rn". */
3870 skip_whitespace (str);
3871
3872 if ((rd = reg_required_here (&str, 16)) == FAIL)
3873 {
3874 inst.error = BAD_ARGS;
3875 return;
3876 }
3877
3878 if (rd == REG_PC)
3879 {
3880 inst.error = BAD_PC;
3881 return;
3882 }
3883
3884 if (skip_past_comma (&str) == FAIL
3885 || (rm = reg_required_here (&str, 0)) == FAIL)
3886 {
3887 inst.error = BAD_ARGS;
3888 return;
3889 }
3890
3891 if (rm == REG_PC)
3892 {
3893 inst.error = BAD_PC;
3894 return;
3895 }
3896
3897 if (rm == rd)
3898 as_tsktsk (_("rd and rm should be different in mla"));
3899
3900 if (skip_past_comma (&str) == FAIL
3901 || (rd = reg_required_here (&str, 8)) == FAIL
3902 || skip_past_comma (&str) == FAIL
3903 || (rm = reg_required_here (&str, 12)) == FAIL)
3904 {
3905 inst.error = BAD_ARGS;
3906 return;
3907 }
3908
3909 if (rd == REG_PC || rm == REG_PC)
3910 {
3911 inst.error = BAD_PC;
3912 return;
3913 }
3914
b99bd4ef
NC
3915 end_of_line (str);
3916 return;
3917}
3918
3919/* Expects *str -> the characters "acc0", possibly with leading blanks.
3920 Advances *str to the next non-alphanumeric.
3921 Returns 0, or else FAIL (in which case sets inst.error).
3922
3923 (In a future XScale, there may be accumulators other than zero.
3924 At that time this routine and its callers can be upgraded to suit.) */
3925
3926static int
3927accum0_required_here (str)
3928 char ** str;
3929{
3930 static char buff [128]; /* Note the address is taken. Hence, static. */
3931 char * p = * str;
3932 char c;
3933 int result = 0; /* The accum number. */
3934
3935 skip_whitespace (p);
3936
3937 *str = p; /* Advance caller's string pointer too. */
3938 c = *p++;
3882b010 3939 while (ISALNUM (c))
b99bd4ef
NC
3940 c = *p++;
3941
3942 *--p = 0; /* Aap nul into input buffer at non-alnum. */
3943
3944 if (! ( streq (*str, "acc0") || streq (*str, "ACC0")))
3945 {
3946 sprintf (buff, _("acc0 expected, not '%.100s'"), *str);
3947 inst.error = buff;
3948 result = FAIL;
3949 }
3950
3951 *p = c; /* Unzap. */
3952 *str = p; /* Caller's string pointer to after match. */
3953 return result;
3954}
3955
3956/* Expects **str -> after a comma. May be leading blanks.
3957 Advances *str, recognizing a load mode, and setting inst.instruction.
3958 Returns rn, or else FAIL (in which case may set inst.error
3959 and not advance str)
3960
3961 Note: doesn't know Rd, so no err checks that require such knowledge. */
3962
3963static int
3964ld_mode_required_here (string)
3965 char ** string;
3966{
3967 char * str = * string;
3968 int rn;
3969 int pre_inc = 0;
3970
3971 skip_whitespace (str);
3972
3973 if (* str == '[')
3974 {
3975 str++;
3976
3977 skip_whitespace (str);
3978
3979 if ((rn = reg_required_here (& str, 16)) == FAIL)
3980 return FAIL;
3981
3982 skip_whitespace (str);
3983
3984 if (* str == ']')
3985 {
3986 str ++;
3987
3988 if (skip_past_comma (& str) == SUCCESS)
3989 {
3990 /* [Rn],... (post inc) */
90e4755a 3991 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
3992 return FAIL;
3993 }
3994 else /* [Rn] */
3995 {
cc8a6dd0 3996 skip_whitespace (str);
b99bd4ef 3997
cc8a6dd0
KH
3998 if (* str == '!')
3999 {
4000 str ++;
4001 inst.instruction |= WRITE_BACK;
4002 }
b99bd4ef
NC
4003
4004 inst.instruction |= INDEX_UP | HWOFFSET_IMM;
4005 pre_inc = 1;
4006 }
4007 }
4008 else /* [Rn,...] */
4009 {
4010 if (skip_past_comma (& str) == FAIL)
4011 {
4012 inst.error = _("pre-indexed expression expected");
4013 return FAIL;
4014 }
4015
4016 pre_inc = 1;
4017
90e4755a 4018 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
4019 return FAIL;
4020
4021 skip_whitespace (str);
4022
4023 if (* str ++ != ']')
4024 {
4025 inst.error = _("missing ]");
4026 return FAIL;
4027 }
4028
4029 skip_whitespace (str);
4030
4031 if (* str == '!')
4032 {
4033 str ++;
4034 inst.instruction |= WRITE_BACK;
4035 }
4036 }
4037 }
4038 else if (* str == '=') /* ldr's "r,=label" syntax */
4039 /* We should never reach here, because <text> = <expression> is
4040 caught gas/read.c read_a_source_file() as a .set operation. */
4041 return FAIL;
4042 else /* PC +- 8 bit immediate offset. */
4043 {
4044 if (my_get_expression (& inst.reloc.exp, & str))
4045 return FAIL;
4046
4047 inst.instruction |= HWOFFSET_IMM; /* The I bit. */
4048 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
4049 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
4050 inst.reloc.pc_rel = 1;
4051 inst.instruction |= (REG_PC << 16);
4052
4053 rn = REG_PC;
4054 pre_inc = 1;
4055 }
4056
4057 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
4058 * string = str;
4059
4060 return rn;
4061}
4062
4063/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
4064 SMLAxy{cond} Rd,Rm,Rs,Rn
4065 SMLAWy{cond} Rd,Rm,Rs,Rn
4066 Error if any register is R15. */
4067
4068static void
f2b7cb0a 4069do_smla (str)
b99bd4ef 4070 char * str;
b99bd4ef
NC
4071{
4072 int rd, rm, rs, rn;
4073
4074 skip_whitespace (str);
4075
4076 if ((rd = reg_required_here (& str, 16)) == FAIL
4077 || skip_past_comma (& str) == FAIL
4078 || (rm = reg_required_here (& str, 0)) == FAIL
4079 || skip_past_comma (& str) == FAIL
4080 || (rs = reg_required_here (& str, 8)) == FAIL
4081 || skip_past_comma (& str) == FAIL
4082 || (rn = reg_required_here (& str, 12)) == FAIL)
4083 inst.error = BAD_ARGS;
4084
4085 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC)
4086 inst.error = BAD_PC;
4087
b99bd4ef
NC
4088 else
4089 end_of_line (str);
4090}
4091
4092/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
4093 SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
4094 Error if any register is R15.
4095 Warning if Rdlo == Rdhi. */
4096
4097static void
f2b7cb0a 4098do_smlal (str)
b99bd4ef 4099 char * str;
b99bd4ef
NC
4100{
4101 int rdlo, rdhi, rm, rs;
4102
4103 skip_whitespace (str);
4104
4105 if ((rdlo = reg_required_here (& str, 12)) == FAIL
4106 || skip_past_comma (& str) == FAIL
4107 || (rdhi = reg_required_here (& str, 16)) == FAIL
4108 || skip_past_comma (& str) == FAIL
4109 || (rm = reg_required_here (& str, 0)) == FAIL
4110 || skip_past_comma (& str) == FAIL
4111 || (rs = reg_required_here (& str, 8)) == FAIL)
4112 {
4113 inst.error = BAD_ARGS;
4114 return;
4115 }
4116
4117 if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
4118 {
4119 inst.error = BAD_PC;
4120 return;
4121 }
4122
4123 if (rdlo == rdhi)
4124 as_tsktsk (_("rdhi and rdlo must be different"));
4125
f2b7cb0a 4126 end_of_line (str);
b99bd4ef
NC
4127}
4128
4129/* ARM V5E (El Segundo) signed-multiply (argument parse)
4130 SMULxy{cond} Rd,Rm,Rs
4131 Error if any register is R15. */
4132
4133static void
f2b7cb0a 4134do_smul (str)
b99bd4ef 4135 char * str;
b99bd4ef
NC
4136{
4137 int rd, rm, rs;
4138
4139 skip_whitespace (str);
4140
4141 if ((rd = reg_required_here (& str, 16)) == FAIL
4142 || skip_past_comma (& str) == FAIL
4143 || (rm = reg_required_here (& str, 0)) == FAIL
4144 || skip_past_comma (& str) == FAIL
4145 || (rs = reg_required_here (& str, 8)) == FAIL)
4146 inst.error = BAD_ARGS;
4147
4148 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC)
4149 inst.error = BAD_PC;
4150
b99bd4ef
NC
4151 else
4152 end_of_line (str);
4153}
4154
4155/* ARM V5E (El Segundo) saturating-add/subtract (argument parse)
4156 Q[D]{ADD,SUB}{cond} Rd,Rm,Rn
4157 Error if any register is R15. */
4158
4159static void
f2b7cb0a 4160do_qadd (str)
b99bd4ef 4161 char * str;
b99bd4ef
NC
4162{
4163 int rd, rm, rn;
4164
4165 skip_whitespace (str);
4166
4167 if ((rd = reg_required_here (& str, 12)) == FAIL
4168 || skip_past_comma (& str) == FAIL
4169 || (rm = reg_required_here (& str, 0)) == FAIL
4170 || skip_past_comma (& str) == FAIL
4171 || (rn = reg_required_here (& str, 16)) == FAIL)
4172 inst.error = BAD_ARGS;
4173
4174 else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
4175 inst.error = BAD_PC;
4176
b99bd4ef
NC
4177 else
4178 end_of_line (str);
4179}
4180
4181/* ARM V5E (el Segundo)
4182 MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
4183 MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
4184
4185 These are equivalent to the XScale instructions MAR and MRA,
4186 respectively, when coproc == 0, opcode == 0, and CRm == 0.
4187
4188 Result unpredicatable if Rd or Rn is R15. */
4189
4190static void
f2b7cb0a 4191do_co_reg2c (str)
b99bd4ef 4192 char * str;
b99bd4ef
NC
4193{
4194 int rd, rn;
4195
4196 skip_whitespace (str);
4197
4198 if (co_proc_number (& str) == FAIL)
4199 {
4200 if (!inst.error)
4201 inst.error = BAD_ARGS;
4202 return;
4203 }
4204
4205 if (skip_past_comma (& str) == FAIL
4206 || cp_opc_expr (& str, 4, 4) == FAIL)
4207 {
4208 if (!inst.error)
4209 inst.error = BAD_ARGS;
4210 return;
4211 }
4212
4213 if (skip_past_comma (& str) == FAIL
4214 || (rd = reg_required_here (& str, 12)) == FAIL)
4215 {
4216 if (!inst.error)
4217 inst.error = BAD_ARGS;
4218 return;
4219 }
4220
4221 if (skip_past_comma (& str) == FAIL
4222 || (rn = reg_required_here (& str, 16)) == FAIL)
4223 {
4224 if (!inst.error)
4225 inst.error = BAD_ARGS;
4226 return;
4227 }
4228
4229 /* Unpredictable result if rd or rn is R15. */
4230 if (rd == REG_PC || rn == REG_PC)
4231 as_tsktsk
f03698e6 4232 (_("Warning: instruction unpredictable when using r15"));
b99bd4ef
NC
4233
4234 if (skip_past_comma (& str) == FAIL
4235 || cp_reg_required_here (& str, 0) == FAIL)
4236 {
4237 if (!inst.error)
4238 inst.error = BAD_ARGS;
4239 return;
4240 }
4241
b99bd4ef
NC
4242 end_of_line (str);
4243}
4244
4245/* ARM V5 count-leading-zeroes instruction (argument parse)
4246 CLZ{<cond>} <Rd>, <Rm>
4247 Condition defaults to COND_ALWAYS.
4248 Error if Rd or Rm are R15. */
4249
4250static void
f2b7cb0a 4251do_clz (str)
b99bd4ef 4252 char * str;
b99bd4ef
NC
4253{
4254 int rd, rm;
4255
b99bd4ef
NC
4256 skip_whitespace (str);
4257
4258 if (((rd = reg_required_here (& str, 12)) == FAIL)
4259 || (skip_past_comma (& str) == FAIL)
4260 || ((rm = reg_required_here (& str, 0)) == FAIL))
4261 inst.error = BAD_ARGS;
4262
4263 else if (rd == REG_PC || rm == REG_PC )
4264 inst.error = BAD_PC;
4265
4266 else
4267 end_of_line (str);
4268}
4269
4270/* ARM V5 (argument parse)
4271 LDC2{L} <coproc>, <CRd>, <addressing mode>
4272 STC2{L} <coproc>, <CRd>, <addressing mode>
4273 Instruction is not conditional, and has 0xf in the codition field.
4274 Otherwise, it's the same as LDC/STC. */
4275
4276static void
f2b7cb0a 4277do_lstc2 (str)
b99bd4ef 4278 char * str;
b99bd4ef 4279{
b99bd4ef
NC
4280 skip_whitespace (str);
4281
4282 if (co_proc_number (& str) == FAIL)
4283 {
4284 if (!inst.error)
4285 inst.error = BAD_ARGS;
4286 }
4287 else if (skip_past_comma (& str) == FAIL
4288 || cp_reg_required_here (& str, 12) == FAIL)
4289 {
4290 if (!inst.error)
4291 inst.error = BAD_ARGS;
4292 }
4293 else if (skip_past_comma (& str) == FAIL
bfae80f2 4294 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
4295 {
4296 if (! inst.error)
4297 inst.error = BAD_ARGS;
4298 }
4299 else
4300 end_of_line (str);
4301}
4302
4303/* ARM V5 (argument parse)
4304 CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
4305 Instruction is not conditional, and has 0xf in the condition field.
4306 Otherwise, it's the same as CDP. */
4307
4308static void
f2b7cb0a 4309do_cdp2 (str)
b99bd4ef 4310 char * str;
b99bd4ef
NC
4311{
4312 skip_whitespace (str);
4313
4314 if (co_proc_number (& str) == FAIL)
4315 {
4316 if (!inst.error)
4317 inst.error = BAD_ARGS;
4318 return;
4319 }
4320
4321 if (skip_past_comma (& str) == FAIL
4322 || cp_opc_expr (& str, 20,4) == FAIL)
4323 {
4324 if (!inst.error)
4325 inst.error = BAD_ARGS;
4326 return;
4327 }
4328
4329 if (skip_past_comma (& str) == FAIL
4330 || cp_reg_required_here (& str, 12) == FAIL)
4331 {
4332 if (!inst.error)
4333 inst.error = BAD_ARGS;
4334 return;
4335 }
4336
4337 if (skip_past_comma (& str) == FAIL
4338 || cp_reg_required_here (& str, 16) == FAIL)
4339 {
4340 if (!inst.error)
4341 inst.error = BAD_ARGS;
4342 return;
4343 }
4344
4345 if (skip_past_comma (& str) == FAIL
4346 || cp_reg_required_here (& str, 0) == FAIL)
4347 {
4348 if (!inst.error)
4349 inst.error = BAD_ARGS;
4350 return;
4351 }
4352
4353 if (skip_past_comma (& str) == SUCCESS)
4354 {
4355 if (cp_opc_expr (& str, 5, 3) == FAIL)
4356 {
4357 if (!inst.error)
4358 inst.error = BAD_ARGS;
4359 return;
4360 }
4361 }
4362
b99bd4ef
NC
4363 end_of_line (str);
4364}
4365
4366/* ARM V5 (argument parse)
4367 MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
4368 MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
4369 Instruction is not conditional, and has 0xf in the condition field.
4370 Otherwise, it's the same as MCR/MRC. */
4371
4372static void
f2b7cb0a 4373do_co_reg2 (str)
b99bd4ef 4374 char * str;
b99bd4ef
NC
4375{
4376 skip_whitespace (str);
4377
4378 if (co_proc_number (& str) == FAIL)
4379 {
4380 if (!inst.error)
4381 inst.error = BAD_ARGS;
4382 return;
4383 }
4384
4385 if (skip_past_comma (& str) == FAIL
4386 || cp_opc_expr (& str, 21, 3) == FAIL)
4387 {
4388 if (!inst.error)
4389 inst.error = BAD_ARGS;
4390 return;
4391 }
4392
4393 if (skip_past_comma (& str) == FAIL
4394 || reg_required_here (& str, 12) == FAIL)
4395 {
4396 if (!inst.error)
4397 inst.error = BAD_ARGS;
4398 return;
4399 }
4400
4401 if (skip_past_comma (& str) == FAIL
4402 || cp_reg_required_here (& str, 16) == FAIL)
4403 {
4404 if (!inst.error)
4405 inst.error = BAD_ARGS;
4406 return;
4407 }
4408
4409 if (skip_past_comma (& str) == FAIL
4410 || cp_reg_required_here (& str, 0) == FAIL)
4411 {
4412 if (!inst.error)
4413 inst.error = BAD_ARGS;
4414 return;
4415 }
4416
4417 if (skip_past_comma (& str) == SUCCESS)
4418 {
4419 if (cp_opc_expr (& str, 5, 3) == FAIL)
4420 {
4421 if (!inst.error)
4422 inst.error = BAD_ARGS;
4423 return;
4424 }
4425 }
4426
b99bd4ef
NC
4427 end_of_line (str);
4428}
4429
ea6ef066
RE
4430/* ARM v5TEJ. Jump to Jazelle code. */
4431static void
4432do_bxj (str)
4433 char * str;
4434{
4435 int reg;
4436
4437 skip_whitespace (str);
4438
4439 if ((reg = reg_required_here (&str, 0)) == FAIL)
4440 {
4441 inst.error = BAD_ARGS;
4442 return;
4443 }
4444
4445 /* Note - it is not illegal to do a "bxj pc". Useless, but not illegal. */
4446 if (reg == REG_PC)
4447 as_tsktsk (_("use of r15 in bxj is not really useful"));
4448
4449 end_of_line (str);
4450}
4451
b99bd4ef
NC
4452/* THUMB V5 breakpoint instruction (argument parse)
4453 BKPT <immed_8>. */
4454
4455static void
4456do_t_bkpt (str)
4457 char * str;
4458{
4459 expressionS expr;
4460 unsigned long number;
4461
4462 skip_whitespace (str);
4463
4464 /* Allow optional leading '#'. */
4465 if (is_immediate_prefix (*str))
4466 str ++;
4467
4468 memset (& expr, '\0', sizeof (expr));
143c8e19
NC
4469 if (my_get_expression (& expr, & str)
4470 || (expr.X_op != O_constant
4471 /* As a convenience we allow 'bkpt' without an operand. */
4472 && expr.X_op != O_absent))
b99bd4ef 4473 {
143c8e19 4474 inst.error = _("bad expression");
b99bd4ef
NC
4475 return;
4476 }
4477
4478 number = expr.X_add_number;
4479
4480 /* Check it fits an 8 bit unsigned. */
4481 if (number != (number & 0xff))
4482 {
4483 inst.error = _("immediate value out of range");
4484 return;
4485 }
4486
4487 inst.instruction |= number;
4488
4489 end_of_line (str);
4490}
4491
4492/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
4493 Expects inst.instruction is set for BLX(1).
4494 Note: this is cloned from do_branch, and the reloc changed to be a
4495 new one that can cope with setting one extra bit (the H bit). */
4496
4497static void
f2b7cb0a 4498do_branch25 (str)
b99bd4ef 4499 char * str;
b99bd4ef
NC
4500{
4501 if (my_get_expression (& inst.reloc.exp, & str))
4502 return;
4503
4504#ifdef OBJ_ELF
4505 {
4506 char * save_in;
4507
4508 /* ScottB: February 5, 1998 */
4509 /* Check to see of PLT32 reloc required for the instruction. */
4510
4511 /* arm_parse_reloc() works on input_line_pointer.
4512 We actually want to parse the operands to the branch instruction
4513 passed in 'str'. Save the input pointer and restore it later. */
4514 save_in = input_line_pointer;
4515 input_line_pointer = str;
4516
4517 if (inst.reloc.exp.X_op == O_symbol
4518 && *str == '('
4519 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
4520 {
4521 inst.reloc.type = BFD_RELOC_ARM_PLT32;
4522 inst.reloc.pc_rel = 0;
4523 /* Modify str to point to after parsed operands, otherwise
4524 end_of_line() will complain about the (PLT) left in str. */
4525 str = input_line_pointer;
4526 }
4527 else
4528 {
4529 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4530 inst.reloc.pc_rel = 1;
4531 }
4532
4533 input_line_pointer = save_in;
4534 }
4535#else
4536 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4537 inst.reloc.pc_rel = 1;
4538#endif /* OBJ_ELF */
4539
4540 end_of_line (str);
4541}
4542
4543/* ARM V5 branch-link-exchange instruction (argument parse)
4544 BLX <target_addr> ie BLX(1)
4545 BLX{<condition>} <Rm> ie BLX(2)
4546 Unfortunately, there are two different opcodes for this mnemonic.
4547 So, the insns[].value is not used, and the code here zaps values
4548 into inst.instruction.
4549 Also, the <target_addr> can be 25 bits, hence has its own reloc. */
4550
4551static void
f2b7cb0a 4552do_blx (str)
b99bd4ef 4553 char * str;
b99bd4ef
NC
4554{
4555 char * mystr = str;
4556 int rm;
4557
b99bd4ef
NC
4558 skip_whitespace (mystr);
4559 rm = reg_required_here (& mystr, 0);
4560
4561 /* The above may set inst.error. Ignore his opinion. */
4562 inst.error = 0;
4563
4564 if (rm != FAIL)
4565 {
4566 /* Arg is a register.
4567 Use the condition code our caller put in inst.instruction.
4568 Pass ourselves off as a BX with a funny opcode. */
4569 inst.instruction |= 0x012fff30;
f2b7cb0a 4570 do_bx (str);
b99bd4ef
NC
4571 }
4572 else
4573 {
4574 /* This must be is BLX <target address>, no condition allowed. */
4575 if (inst.instruction != COND_ALWAYS)
cc8a6dd0
KH
4576 {
4577 inst.error = BAD_COND;
b99bd4ef 4578 return;
cc8a6dd0 4579 }
b99bd4ef
NC
4580
4581 inst.instruction = 0xfafffffe;
4582
4583 /* Process like a B/BL, but with a different reloc.
4584 Note that B/BL expecte fffffe, not 0, offset in the opcode table. */
f2b7cb0a 4585 do_branch25 (str);
b99bd4ef
NC
4586 }
4587}
4588
4589/* ARM V5 Thumb BLX (argument parse)
4590 BLX <target_addr> which is BLX(1)
4591 BLX <Rm> which is BLX(2)
4592 Unfortunately, there are two different opcodes for this mnemonic.
4593 So, the tinsns[].value is not used, and the code here zaps values
4594 into inst.instruction. */
4595
4596static void
4597do_t_blx (str)
4598 char * str;
4599{
4600 char * mystr = str;
4601 int rm;
4602
4603 skip_whitespace (mystr);
4604 inst.instruction = 0x4780;
4605
4606 /* Note that this call is to the ARM register recognizer. BLX(2)
4607 uses the ARM register space, not the Thumb one, so a call to
4608 thumb_reg() would be wrong. */
4609 rm = reg_required_here (& mystr, 3);
4610 inst.error = 0;
4611
4612 if (rm != FAIL)
4613 {
4614 /* It's BLX(2). The .instruction was zapped with rm & is final. */
4615 inst.size = 2;
4616 }
4617 else
4618 {
4619 /* No ARM register. This must be BLX(1). Change the .instruction. */
4620 inst.instruction = 0xf7ffeffe;
4621 inst.size = 4;
4622
4623 if (my_get_expression (& inst.reloc.exp, & mystr))
4624 return;
4625
4626 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
4627 inst.reloc.pc_rel = 1;
4628 }
4629
4630 end_of_line (mystr);
4631}
4632
4633/* ARM V5 breakpoint instruction (argument parse)
4634 BKPT <16 bit unsigned immediate>
4635 Instruction is not conditional.
4636 The bit pattern given in insns[] has the COND_ALWAYS condition,
cc8a6dd0 4637 and it is an error if the caller tried to override that. */
b99bd4ef
NC
4638
4639static void
f2b7cb0a 4640do_bkpt (str)
b99bd4ef 4641 char * str;
b99bd4ef
NC
4642{
4643 expressionS expr;
4644 unsigned long number;
4645
4646 skip_whitespace (str);
4647
4648 /* Allow optional leading '#'. */
4649 if (is_immediate_prefix (* str))
4650 str++;
4651
4652 memset (& expr, '\0', sizeof (expr));
4653
143c8e19
NC
4654 if (my_get_expression (& expr, & str)
4655 || (expr.X_op != O_constant
4656 /* As a convenience we allow 'bkpt' without an operand. */
4657 && expr.X_op != O_absent))
b99bd4ef 4658 {
143c8e19 4659 inst.error = _("bad expression");
b99bd4ef
NC
4660 return;
4661 }
4662
4663 number = expr.X_add_number;
4664
4665 /* Check it fits a 16 bit unsigned. */
4666 if (number != (number & 0xffff))
4667 {
4668 inst.error = _("immediate value out of range");
4669 return;
4670 }
4671
4672 /* Top 12 of 16 bits to bits 19:8. */
4673 inst.instruction |= (number & 0xfff0) << 4;
4674
4675 /* Bottom 4 of 16 bits to bits 3:0. */
4676 inst.instruction |= number & 0xf;
4677
4678 end_of_line (str);
b99bd4ef
NC
4679}
4680
e16bb312
NC
4681static unsigned long check_iwmmxt_insn PARAMS ((char *, enum iwmmxt_insn_type, int));
4682
4683/* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate. */
4684
4685static unsigned long
4686check_iwmmxt_insn (str, insn_type, immediate_size)
4687 char * str;
4688 enum iwmmxt_insn_type insn_type;
4689 int immediate_size;
4690{
4691 int reg = 0;
4692 const char * inst_error;
4693 expressionS expr;
4694 unsigned long number;
4695
4696 inst_error = inst.error;
4697 if (!inst.error)
4698 inst.error = BAD_ARGS;
4699 skip_whitespace (str);
4700
4701 switch (insn_type)
4702 {
4703 case check_rd:
4704 if ((reg = reg_required_here (&str, 12)) == FAIL)
4705 return FAIL;
4706 break;
4707
4708 case check_wr:
4709 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR)) == FAIL)
4710 return FAIL;
4711 break;
4712
4713 case check_wrwr:
4714 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4715 || skip_past_comma (&str) == FAIL
4716 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
4717 return FAIL;
4718 break;
4719
4720 case check_wrwrwr:
4721 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4722 || skip_past_comma (&str) == FAIL
4723 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4724 || skip_past_comma (&str) == FAIL
4725 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
4726 return FAIL;
4727 break;
4728
4729 case check_wrwrwcg:
4730 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4731 || skip_past_comma (&str) == FAIL
4732 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4733 || skip_past_comma (&str) == FAIL
4734 || wreg_required_here (&str, 0, IWMMXT_REG_WCG) == FAIL))
4735 return FAIL;
4736 break;
4737
4738 case check_tbcst:
4739 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4740 || skip_past_comma (&str) == FAIL
4741 || reg_required_here (&str, 12) == FAIL))
4742 return FAIL;
4743 break;
4744
4745 case check_tmovmsk:
4746 if ((reg_required_here (&str, 12) == FAIL
4747 || skip_past_comma (&str) == FAIL
4748 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
4749 return FAIL;
4750 break;
4751
4752 case check_tmia:
4753 if ((wreg_required_here (&str, 5, IWMMXT_REG_WR) == FAIL
4754 || skip_past_comma (&str) == FAIL
4755 || reg_required_here (&str, 0) == FAIL
4756 || skip_past_comma (&str) == FAIL
4757 || reg_required_here (&str, 12) == FAIL))
4758 return FAIL;
4759 break;
4760
4761 case check_tmcrr:
4762 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
4763 || skip_past_comma (&str) == FAIL
4764 || reg_required_here (&str, 12) == FAIL
4765 || skip_past_comma (&str) == FAIL
4766 || reg_required_here (&str, 16) == FAIL))
4767 return FAIL;
4768 break;
4769
4770 case check_tmrrc:
4771 if ((reg_required_here (&str, 12) == FAIL
4772 || skip_past_comma (&str) == FAIL
4773 || reg_required_here (&str, 16) == FAIL
4774 || skip_past_comma (&str) == FAIL
4775 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
4776 return FAIL;
4777 break;
4778
4779 case check_tmcr:
4780 if ((wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL
4781 || skip_past_comma (&str) == FAIL
4782 || reg_required_here (&str, 12) == FAIL))
4783 return FAIL;
4784 break;
4785
4786 case check_tmrc:
4787 if ((reg_required_here (&str, 12) == FAIL
4788 || skip_past_comma (&str) == FAIL
4789 || wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL))
4790 return FAIL;
4791 break;
4792
4793 case check_tinsr:
4794 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4795 || skip_past_comma (&str) == FAIL
4796 || reg_required_here (&str, 12) == FAIL
4797 || skip_past_comma (&str) == FAIL))
4798 return FAIL;
4799 break;
4800
4801 case check_textrc:
4802 if ((reg_required_here (&str, 12) == FAIL
4803 || skip_past_comma (&str) == FAIL))
4804 return FAIL;
4805 break;
4806
4807 case check_waligni:
4808 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4809 || skip_past_comma (&str) == FAIL
4810 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4811 || skip_past_comma (&str) == FAIL
4812 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
4813 || skip_past_comma (&str) == FAIL))
4814 return FAIL;
4815 break;
4816
4817 case check_textrm:
4818 if ((reg_required_here (&str, 12) == FAIL
4819 || skip_past_comma (&str) == FAIL
4820 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4821 || skip_past_comma (&str) == FAIL))
4822 return FAIL;
4823 break;
4824
4825 case check_wshufh:
4826 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4827 || skip_past_comma (&str) == FAIL
4828 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4829 || skip_past_comma (&str) == FAIL))
4830 return FAIL;
4831 break;
4832 }
4833
4834 if (immediate_size == 0)
4835 {
4836 end_of_line (str);
4837 inst.error = inst_error;
4838 return reg;
4839 }
4840 else
4841 {
4842 skip_whitespace (str);
4843
4844 /* Allow optional leading '#'. */
4845 if (is_immediate_prefix (* str))
4846 str++;
4847
4848 memset (& expr, '\0', sizeof (expr));
4849
4850 if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
4851 {
4852 inst.error = _("bad or missing expression");
4853 return FAIL;
4854 }
4855
4856 number = expr.X_add_number;
4857
4858 if (number != (number & immediate_size))
4859 {
4860 inst.error = _("immediate value out of range");
4861 return FAIL;
4862 }
4863 end_of_line (str);
4864 inst.error = inst_error;
4865 return number;
4866 }
4867}
4868
4869static void
4870do_iwmmxt_byte_addr (str)
4871 char * str;
4872{
4873 int op = (inst.instruction & 0x300) >> 8;
4874 int reg;
4875
4876 inst.instruction &= ~0x300;
4877 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
4878
4879 skip_whitespace (str);
4880
4881 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
4882 || skip_past_comma (& str) == FAIL
4883 || cp_byte_address_required_here (&str) == FAIL)
4884 {
4885 if (! inst.error)
4886 inst.error = BAD_ARGS;
4887 }
4888 else
4889 end_of_line (str);
4890
4891 if (wc_register (reg))
4892 {
4893 inst.instruction |= 0xf0000100;
4894 inst.instruction &= ~0x00400000;
4895 }
4896}
4897
4898static void
4899do_iwmmxt_tandc (str)
4900 char * str;
4901{
4902 int reg;
4903
4904 reg = check_iwmmxt_insn (str, check_rd, 0);
4905
4906 if (reg != REG_PC && !inst.error)
4907 inst.error = _("only r15 allowed here");
4908 return;
4909}
4910
4911static void
4912do_iwmmxt_tbcst (str)
4913 char * str;
4914{
4915 check_iwmmxt_insn (str, check_tbcst, 0);
4916
4917 return;
4918}
4919
4920static void
4921do_iwmmxt_textrc (str)
4922 char * str;
4923{
4924 unsigned long number;
4925
4926 if ((number = check_iwmmxt_insn (str, check_textrc, 7)) == (unsigned long) FAIL)
4927 return;
4928
4929 inst.instruction |= number & 0x7;
4930 return;
4931}
4932
4933static void
4934do_iwmmxt_textrm (str)
4935 char * str;
4936{
4937 unsigned long number;
4938
4939 if ((number = check_iwmmxt_insn (str, check_textrm, 7)) == (unsigned long) FAIL)
4940 return;
4941
4942 inst.instruction |= number & 0x7;
4943}
4944
4945static void
4946do_iwmmxt_tinsr (str)
4947 char * str;
4948{
4949 unsigned long number;
4950
4951 if ((number = check_iwmmxt_insn (str, check_tinsr, 7)) == (unsigned long) FAIL)
4952 return;
4953
4954 inst.instruction |= number & 0x7;
4955 return;
4956}
4957
4958static void
4959do_iwmmxt_tmcr (str)
4960 char * str;
4961{
4962 check_iwmmxt_insn (str, check_tmcr, 0);
4963
4964 return;
4965}
4966
4967static void
4968do_iwmmxt_tmcrr (str)
4969 char * str;
4970{
4971 check_iwmmxt_insn (str, check_tmcrr, 0);
4972
4973 return;
4974}
4975
4976static void
4977do_iwmmxt_tmia (str)
4978 char * str;
4979{
4980 check_iwmmxt_insn (str, check_tmia, 0);
4981
4982 return;
4983}
4984
4985static void
4986do_iwmmxt_tmovmsk (str)
4987 char * str;
4988{
4989 check_iwmmxt_insn (str, check_tmovmsk, 0);
4990
4991 return;
4992}
4993
4994static void
4995do_iwmmxt_tmrc (str)
4996 char * str;
4997{
4998 check_iwmmxt_insn (str, check_tmrc, 0);
4999
5000 return;
5001}
5002
5003static void
5004do_iwmmxt_tmrrc (str)
5005 char * str;
5006{
5007 check_iwmmxt_insn (str, check_tmrrc, 0);
5008
5009 return;
5010}
5011
5012static void
5013do_iwmmxt_torc (str)
5014 char * str;
5015{
5016 check_iwmmxt_insn (str, check_rd, 0);
5017 return;
5018}
5019
5020static void
5021do_iwmmxt_waligni (str)
5022 char * str;
5023{
5024 unsigned long number;
5025
5026 if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL)
5027 return;
5028
5029 inst.instruction |= ((number & 0x7) << 20);
5030 return;
5031}
5032
5033static void
5034do_iwmmxt_wmov (str)
5035 char * str;
5036{
5037 if (check_iwmmxt_insn (str, check_wrwr, 0) == (unsigned long) FAIL)
5038 return;
5039
5040 inst.instruction |= ((inst.instruction >> 16) & 0xf);
5041 return;
5042}
5043
5044static void
5045do_iwmmxt_word_addr (str)
5046 char * str;
5047{
5048 int op = (inst.instruction & 0x300) >> 8;
5049 int reg;
5050
5051 inst.instruction &= ~0x300;
5052 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
5053
5054 skip_whitespace (str);
5055
5056 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
5057 || skip_past_comma (& str) == FAIL
5058 || cp_address_required_here (& str, CP_WB_OK) == FAIL)
5059 {
5060 if (! inst.error)
5061 inst.error = BAD_ARGS;
5062 }
5063 else
5064 end_of_line (str);
5065
5066 if (wc_register (reg))
5067 {
5068 inst.instruction |= 0xf0000100;
5069 inst.instruction &= ~0x00400000;
5070 }
5071}
5072
5073static void
5074do_iwmmxt_wrwr (str)
5075 char * str;
5076{
5077 check_iwmmxt_insn (str, check_wrwr, 0);
5078
5079 return;
5080}
5081
5082static void
5083do_iwmmxt_wrwrwcg (str)
5084 char * str;
5085{
5086 check_iwmmxt_insn (str, check_wrwrwcg, 0);
5087
5088 return;
5089}
5090
5091static void
5092do_iwmmxt_wrwrwr (str)
5093 char * str;
5094{
5095 check_iwmmxt_insn (str, check_wrwrwr, 0);
5096
5097 return;
5098}
5099
5100static void
5101do_iwmmxt_wshufh (str)
5102 char * str;
5103{
5104 unsigned long number;
5105
5106 if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL)
5107 return;
5108
5109 inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf);
5110 return;
5111}
5112
5113static void
5114do_iwmmxt_wzero (str)
5115 char * str;
5116{
5117 if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL)
5118 return;
5119
5120 inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16);
5121 return;
5122}
5123
b99bd4ef
NC
5124/* Xscale multiply-accumulate (argument parse)
5125 MIAcc acc0,Rm,Rs
5126 MIAPHcc acc0,Rm,Rs
5127 MIAxycc acc0,Rm,Rs. */
5128
5129static void
63e63b07 5130do_xsc_mia (str)
b99bd4ef 5131 char * str;
b99bd4ef
NC
5132{
5133 int rs;
5134 int rm;
5135
f2b7cb0a 5136 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5137 inst.error = ERR_NO_ACCUM;
5138
5139 else if (skip_past_comma (& str) == FAIL
5140 || (rm = reg_required_here (& str, 0)) == FAIL)
5141 inst.error = BAD_ARGS;
5142
5143 else if (skip_past_comma (& str) == FAIL
5144 || (rs = reg_required_here (& str, 12)) == FAIL)
5145 inst.error = BAD_ARGS;
5146
5147 /* inst.instruction has now been zapped with both rm and rs. */
5148 else if (rm == REG_PC || rs == REG_PC)
5149 inst.error = BAD_PC; /* Undefined result if rm or rs is R15. */
5150
5151 else
5152 end_of_line (str);
5153}
5154
5155/* Xscale move-accumulator-register (argument parse)
5156
5157 MARcc acc0,RdLo,RdHi. */
5158
5159static void
63e63b07 5160do_xsc_mar (str)
b99bd4ef 5161 char * str;
b99bd4ef
NC
5162{
5163 int rdlo, rdhi;
5164
f2b7cb0a 5165 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5166 inst.error = ERR_NO_ACCUM;
5167
5168 else if (skip_past_comma (& str) == FAIL
5169 || (rdlo = reg_required_here (& str, 12)) == FAIL)
5170 inst.error = BAD_ARGS;
5171
5172 else if (skip_past_comma (& str) == FAIL
5173 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5174 inst.error = BAD_ARGS;
5175
5176 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5177 else if (rdlo == REG_PC || rdhi == REG_PC)
5178 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5179
5180 else
5181 end_of_line (str);
5182}
5183
5184/* Xscale move-register-accumulator (argument parse)
5185
5186 MRAcc RdLo,RdHi,acc0. */
5187
5188static void
63e63b07 5189do_xsc_mra (str)
b99bd4ef 5190 char * str;
b99bd4ef
NC
5191{
5192 int rdlo;
5193 int rdhi;
5194
b99bd4ef
NC
5195 skip_whitespace (str);
5196
5197 if ((rdlo = reg_required_here (& str, 12)) == FAIL)
5198 inst.error = BAD_ARGS;
5199
5200 else if (skip_past_comma (& str) == FAIL
5201 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5202 inst.error = BAD_ARGS;
5203
5204 else if (skip_past_comma (& str) == FAIL
5205 || accum0_required_here (& str) == FAIL)
5206 inst.error = ERR_NO_ACCUM;
5207
5208 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5209 else if (rdlo == rdhi)
5210 inst.error = BAD_ARGS; /* Undefined result if 2 writes to same reg. */
5211
5212 else if (rdlo == REG_PC || rdhi == REG_PC)
5213 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5214 else
5215 end_of_line (str);
5216}
5217
c9b604bd 5218/* ARMv5TE: Preload-Cache
b99bd4ef
NC
5219
5220 PLD <addr_mode>
5221
5222 Syntactically, like LDR with B=1, W=0, L=1. */
5223
5224static void
f2b7cb0a 5225do_pld (str)
b99bd4ef 5226 char * str;
b99bd4ef
NC
5227{
5228 int rd;
5229
b99bd4ef
NC
5230 skip_whitespace (str);
5231
5232 if (* str != '[')
5233 {
5234 inst.error = _("'[' expected after PLD mnemonic");
5235 return;
5236 }
5237
90e4755a 5238 ++str;
b99bd4ef
NC
5239 skip_whitespace (str);
5240
5241 if ((rd = reg_required_here (& str, 16)) == FAIL)
5242 return;
5243
5244 skip_whitespace (str);
5245
90e4755a 5246 if (*str == ']')
b99bd4ef
NC
5247 {
5248 /* [Rn], ... ? */
90e4755a 5249 ++str;
b99bd4ef
NC
5250 skip_whitespace (str);
5251
90e4755a
RE
5252 /* Post-indexed addressing is not allowed with PLD. */
5253 if (skip_past_comma (&str) == SUCCESS)
b99bd4ef 5254 {
90e4755a
RE
5255 inst.error
5256 = _("post-indexed expression used in preload instruction");
5257 return;
b99bd4ef 5258 }
90e4755a 5259 else if (*str == '!') /* [Rn]! */
b99bd4ef
NC
5260 {
5261 inst.error = _("writeback used in preload instruction");
90e4755a 5262 ++str;
b99bd4ef
NC
5263 }
5264 else /* [Rn] */
5265 inst.instruction |= INDEX_UP | PRE_INDEX;
5266 }
5267 else /* [Rn, ...] */
5268 {
5269 if (skip_past_comma (& str) == FAIL)
5270 {
5271 inst.error = _("pre-indexed expression expected");
5272 return;
5273 }
5274
90e4755a 5275 if (ldst_extend (&str) == FAIL)
b99bd4ef
NC
5276 return;
5277
5278 skip_whitespace (str);
5279
5280 if (* str != ']')
5281 {
5282 inst.error = _("missing ]");
5283 return;
5284 }
5285
5286 ++ str;
5287 skip_whitespace (str);
5288
5289 if (* str == '!') /* [Rn]! */
5290 {
5291 inst.error = _("writeback used in preload instruction");
5292 ++ str;
5293 }
5294
5295 inst.instruction |= PRE_INDEX;
5296 }
5297
5298 end_of_line (str);
5299}
5300
c9b604bd 5301/* ARMv5TE load-consecutive (argument parse)
b99bd4ef
NC
5302 Mode is like LDRH.
5303
5304 LDRccD R, mode
5305 STRccD R, mode. */
5306
5307static void
f2b7cb0a 5308do_ldrd (str)
b99bd4ef 5309 char * str;
b99bd4ef
NC
5310{
5311 int rd;
5312 int rn;
5313
b99bd4ef
NC
5314 skip_whitespace (str);
5315
5316 if ((rd = reg_required_here (& str, 12)) == FAIL)
5317 {
5318 inst.error = BAD_ARGS;
5319 return;
5320 }
5321
5322 if (skip_past_comma (& str) == FAIL
5323 || (rn = ld_mode_required_here (& str)) == FAIL)
5324 {
5325 if (!inst.error)
cc8a6dd0 5326 inst.error = BAD_ARGS;
b99bd4ef
NC
5327 return;
5328 }
5329
5330 /* inst.instruction has now been zapped with Rd and the addressing mode. */
5331 if (rd & 1) /* Unpredictable result if Rd is odd. */
5332 {
f03698e6 5333 inst.error = _("destination register must be even");
b99bd4ef
NC
5334 return;
5335 }
5336
90e4755a 5337 if (rd == REG_LR)
b99bd4ef 5338 {
f2b7cb0a 5339 inst.error = _("r14 not allowed here");
b99bd4ef
NC
5340 return;
5341 }
5342
5343 if (((rd == rn) || (rd + 1 == rn))
90e4755a
RE
5344 && ((inst.instruction & WRITE_BACK)
5345 || (!(inst.instruction & PRE_INDEX))))
b99bd4ef
NC
5346 as_warn (_("pre/post-indexing used when modified address register is destination"));
5347
90e4755a
RE
5348 /* For an index-register load, the index register must not overlap the
5349 destination (even if not write-back). */
5350 if ((inst.instruction & V4_STR_BIT) == 0
5351 && (inst.instruction & HWOFFSET_IMM) == 0)
5352 {
5353 int rm = inst.instruction & 0x0000000f;
5354
5355 if (rm == rd || (rm == rd + 1))
5356 as_warn (_("ldrd destination registers must not overlap index register"));
5357 }
5358
b99bd4ef
NC
5359 end_of_line (str);
5360}
5361
5362/* Returns the index into fp_values of a floating point number,
5363 or -1 if not in the table. */
5364
5365static int
5366my_get_float_expression (str)
5367 char ** str;
5368{
5369 LITTLENUM_TYPE words[MAX_LITTLENUMS];
5370 char * save_in;
5371 expressionS exp;
5372 int i;
5373 int j;
5374
5375 memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
5376
5377 /* Look for a raw floating point number. */
5378 if ((save_in = atof_ieee (*str, 'x', words)) != NULL
5379 && is_end_of_line[(unsigned char) *save_in])
5380 {
5381 for (i = 0; i < NUM_FLOAT_VALS; i++)
5382 {
5383 for (j = 0; j < MAX_LITTLENUMS; j++)
5384 {
5385 if (words[j] != fp_values[i][j])
5386 break;
5387 }
5388
5389 if (j == MAX_LITTLENUMS)
5390 {
5391 *str = save_in;
5392 return i;
5393 }
5394 }
5395 }
5396
5397 /* Try and parse a more complex expression, this will probably fail
5398 unless the code uses a floating point prefix (eg "0f"). */
5399 save_in = input_line_pointer;
5400 input_line_pointer = *str;
5401 if (expression (&exp) == absolute_section
5402 && exp.X_op == O_big
5403 && exp.X_add_number < 0)
5404 {
5405 /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
5406 Ditto for 15. */
5407 if (gen_to_words (words, 5, (long) 15) == 0)
5408 {
5409 for (i = 0; i < NUM_FLOAT_VALS; i++)
5410 {
5411 for (j = 0; j < MAX_LITTLENUMS; j++)
5412 {
5413 if (words[j] != fp_values[i][j])
5414 break;
5415 }
5416
5417 if (j == MAX_LITTLENUMS)
5418 {
5419 *str = input_line_pointer;
5420 input_line_pointer = save_in;
5421 return i;
5422 }
5423 }
5424 }
5425 }
5426
5427 *str = input_line_pointer;
5428 input_line_pointer = save_in;
5429 return -1;
5430}
5431
b34976b6 5432/* Return TRUE if anything in the expression is a bignum. */
b99bd4ef
NC
5433
5434static int
5435walk_no_bignums (sp)
5436 symbolS * sp;
5437{
5438 if (symbol_get_value_expression (sp)->X_op == O_big)
5439 return 1;
5440
5441 if (symbol_get_value_expression (sp)->X_add_symbol)
5442 {
5443 return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
5444 || (symbol_get_value_expression (sp)->X_op_symbol
5445 && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
5446 }
5447
5448 return 0;
5449}
5450
f03698e6
RE
5451static int in_my_get_expression = 0;
5452
b99bd4ef
NC
5453static int
5454my_get_expression (ep, str)
5455 expressionS * ep;
5456 char ** str;
5457{
5458 char * save_in;
5459 segT seg;
5460
5461 save_in = input_line_pointer;
5462 input_line_pointer = *str;
f03698e6 5463 in_my_get_expression = 1;
b99bd4ef 5464 seg = expression (ep);
f03698e6
RE
5465 in_my_get_expression = 0;
5466
5467 if (ep->X_op == O_illegal)
5468 {
5469 /* We found a bad expression in md_operand(). */
5470 *str = input_line_pointer;
5471 input_line_pointer = save_in;
5472 return 1;
5473 }
b99bd4ef
NC
5474
5475#ifdef OBJ_AOUT
5476 if (seg != absolute_section
5477 && seg != text_section
5478 && seg != data_section
5479 && seg != bss_section
5480 && seg != undefined_section)
5481 {
5482 inst.error = _("bad_segment");
5483 *str = input_line_pointer;
5484 input_line_pointer = save_in;
5485 return 1;
5486 }
5487#endif
5488
5489 /* Get rid of any bignums now, so that we don't generate an error for which
5490 we can't establish a line number later on. Big numbers are never valid
5491 in instructions, which is where this routine is always called. */
5492 if (ep->X_op == O_big
5493 || (ep->X_add_symbol
5494 && (walk_no_bignums (ep->X_add_symbol)
5495 || (ep->X_op_symbol
5496 && walk_no_bignums (ep->X_op_symbol)))))
5497 {
f03698e6 5498 inst.error = _("invalid constant");
b99bd4ef
NC
5499 *str = input_line_pointer;
5500 input_line_pointer = save_in;
5501 return 1;
5502 }
5503
5504 *str = input_line_pointer;
5505 input_line_pointer = save_in;
5506 return 0;
5507}
5508
cc8a6dd0 5509/* We handle all bad expressions here, so that we can report the faulty
f03698e6
RE
5510 instruction in the error message. */
5511void
ce058b6c 5512md_operand (expr)
f03698e6
RE
5513 expressionS *expr;
5514{
5515 if (in_my_get_expression)
5516 {
5517 expr->X_op = O_illegal;
5518 if (inst.error == NULL)
5519 inst.error = _("bad expression");
5520 }
5521}
5522
b99bd4ef
NC
5523/* UNRESTRICT should be one if <shift> <register> is permitted for this
5524 instruction. */
5525
5526static int
5527decode_shift (str, unrestrict)
5528 char ** str;
5529 int unrestrict;
5530{
5531 const struct asm_shift_name * shift;
5532 char * p;
5533 char c;
5534
5535 skip_whitespace (* str);
5536
3882b010 5537 for (p = * str; ISALPHA (* p); p ++)
b99bd4ef
NC
5538 ;
5539
5540 if (p == * str)
5541 {
f03698e6 5542 inst.error = _("shift expression expected");
b99bd4ef
NC
5543 return FAIL;
5544 }
5545
5546 c = * p;
5547 * p = '\0';
5548 shift = (const struct asm_shift_name *) hash_find (arm_shift_hsh, * str);
5549 * p = c;
5550
5551 if (shift == NULL)
5552 {
f03698e6 5553 inst.error = _("shift expression expected");
b99bd4ef
NC
5554 return FAIL;
5555 }
5556
5557 assert (shift->properties->index == shift_properties[shift->properties->index].index);
5558
5559 if (shift->properties->index == SHIFT_RRX)
5560 {
5561 * str = p;
5562 inst.instruction |= shift->properties->bit_field;
5563 return SUCCESS;
5564 }
5565
5566 skip_whitespace (p);
5567
5568 if (unrestrict && reg_required_here (& p, 8) != FAIL)
5569 {
5570 inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG;
5571 * str = p;
5572 return SUCCESS;
5573 }
5574 else if (! is_immediate_prefix (* p))
5575 {
5576 inst.error = (unrestrict
5577 ? _("shift requires register or #expression")
5578 : _("shift requires #expression"));
5579 * str = p;
5580 return FAIL;
5581 }
5582
5583 inst.error = NULL;
5584 p ++;
5585
5586 if (my_get_expression (& inst.reloc.exp, & p))
5587 return FAIL;
5588
5589 /* Validate some simple #expressions. */
5590 if (inst.reloc.exp.X_op == O_constant)
5591 {
5592 unsigned num = inst.reloc.exp.X_add_number;
5593
5594 /* Reject operations greater than 32. */
5595 if (num > 32
5596 /* Reject a shift of 0 unless the mode allows it. */
5597 || (num == 0 && shift->properties->allows_0 == 0)
5598 /* Reject a shift of 32 unless the mode allows it. */
5599 || (num == 32 && shift->properties->allows_32 == 0)
5600 )
5601 {
5602 /* As a special case we allow a shift of zero for
5603 modes that do not support it to be recoded as an
5604 logical shift left of zero (ie nothing). We warn
5605 about this though. */
5606 if (num == 0)
5607 {
f03698e6 5608 as_warn (_("shift of 0 ignored."));
b99bd4ef
NC
5609 shift = & shift_names[0];
5610 assert (shift->properties->index == SHIFT_LSL);
5611 }
5612 else
5613 {
f03698e6 5614 inst.error = _("invalid immediate shift");
b99bd4ef
NC
5615 return FAIL;
5616 }
5617 }
5618
5619 /* Shifts of 32 are encoded as 0, for those shifts that
5620 support it. */
5621 if (num == 32)
5622 num = 0;
5623
5624 inst.instruction |= (num << 7) | shift->properties->bit_field;
5625 }
5626 else
5627 {
5628 inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
5629 inst.reloc.pc_rel = 0;
5630 inst.instruction |= shift->properties->bit_field;
5631 }
5632
5633 * str = p;
5634 return SUCCESS;
5635}
5636
5637/* Do those data_ops which can take a negative immediate constant
5638 by altering the instuction. A bit of a hack really.
5639 MOV <-> MVN
5640 AND <-> BIC
5641 ADC <-> SBC
5642 by inverting the second operand, and
5643 ADD <-> SUB
5644 CMP <-> CMN
5645 by negating the second operand. */
5646
5647static int
5648negate_data_op (instruction, value)
5649 unsigned long * instruction;
5650 unsigned long value;
5651{
5652 int op, new_inst;
5653 unsigned long negated, inverted;
5654
5655 negated = validate_immediate (-value);
5656 inverted = validate_immediate (~value);
5657
5658 op = (*instruction >> DATA_OP_SHIFT) & 0xf;
5659 switch (op)
5660 {
5661 /* First negates. */
5662 case OPCODE_SUB: /* ADD <-> SUB */
5663 new_inst = OPCODE_ADD;
5664 value = negated;
5665 break;
5666
5667 case OPCODE_ADD:
5668 new_inst = OPCODE_SUB;
5669 value = negated;
5670 break;
5671
5672 case OPCODE_CMP: /* CMP <-> CMN */
5673 new_inst = OPCODE_CMN;
5674 value = negated;
5675 break;
5676
5677 case OPCODE_CMN:
5678 new_inst = OPCODE_CMP;
5679 value = negated;
5680 break;
5681
5682 /* Now Inverted ops. */
5683 case OPCODE_MOV: /* MOV <-> MVN */
5684 new_inst = OPCODE_MVN;
5685 value = inverted;
5686 break;
5687
5688 case OPCODE_MVN:
5689 new_inst = OPCODE_MOV;
5690 value = inverted;
5691 break;
5692
5693 case OPCODE_AND: /* AND <-> BIC */
5694 new_inst = OPCODE_BIC;
5695 value = inverted;
5696 break;
5697
5698 case OPCODE_BIC:
5699 new_inst = OPCODE_AND;
5700 value = inverted;
5701 break;
5702
5703 case OPCODE_ADC: /* ADC <-> SBC */
5704 new_inst = OPCODE_SBC;
5705 value = inverted;
5706 break;
5707
5708 case OPCODE_SBC:
5709 new_inst = OPCODE_ADC;
5710 value = inverted;
5711 break;
5712
5713 /* We cannot do anything. */
5714 default:
5715 return FAIL;
5716 }
5717
5718 if (value == (unsigned) FAIL)
5719 return FAIL;
5720
5721 *instruction &= OPCODE_MASK;
5722 *instruction |= new_inst << DATA_OP_SHIFT;
5723 return value;
5724}
5725
5726static int
5727data_op2 (str)
5728 char ** str;
5729{
5730 int value;
5731 expressionS expr;
5732
5733 skip_whitespace (* str);
5734
5735 if (reg_required_here (str, 0) != FAIL)
5736 {
5737 if (skip_past_comma (str) == SUCCESS)
5738 /* Shift operation on register. */
5739 return decode_shift (str, NO_SHIFT_RESTRICT);
5740
5741 return SUCCESS;
5742 }
5743 else
5744 {
5745 /* Immediate expression. */
5746 if (is_immediate_prefix (**str))
5747 {
5748 (*str)++;
5749 inst.error = NULL;
5750
5751 if (my_get_expression (&inst.reloc.exp, str))
5752 return FAIL;
5753
5754 if (inst.reloc.exp.X_add_symbol)
5755 {
5756 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
5757 inst.reloc.pc_rel = 0;
5758 }
5759 else
5760 {
5761 if (skip_past_comma (str) == SUCCESS)
5762 {
5763 /* #x, y -- ie explicit rotation by Y. */
5764 if (my_get_expression (&expr, str))
5765 return FAIL;
5766
5767 if (expr.X_op != O_constant)
5768 {
f03698e6 5769 inst.error = _("constant expression expected");
b99bd4ef
NC
5770 return FAIL;
5771 }
5772
5773 /* Rotate must be a multiple of 2. */
5774 if (((unsigned) expr.X_add_number) > 30
5775 || (expr.X_add_number & 1) != 0
5776 || ((unsigned) inst.reloc.exp.X_add_number) > 255)
5777 {
f03698e6 5778 inst.error = _("invalid constant");
b99bd4ef
NC
5779 return FAIL;
5780 }
5781 inst.instruction |= INST_IMMEDIATE;
5782 inst.instruction |= inst.reloc.exp.X_add_number;
5783 inst.instruction |= expr.X_add_number << 7;
5784 return SUCCESS;
5785 }
5786
5787 /* Implicit rotation, select a suitable one. */
5788 value = validate_immediate (inst.reloc.exp.X_add_number);
5789
5790 if (value == FAIL)
5791 {
5792 /* Can't be done. Perhaps the code reads something like
5793 "add Rd, Rn, #-n", where "sub Rd, Rn, #n" would be OK. */
5794 if ((value = negate_data_op (&inst.instruction,
5795 inst.reloc.exp.X_add_number))
5796 == FAIL)
5797 {
f03698e6 5798 inst.error = _("invalid constant");
b99bd4ef
NC
5799 return FAIL;
5800 }
5801 }
5802
5803 inst.instruction |= value;
5804 }
5805
5806 inst.instruction |= INST_IMMEDIATE;
5807 return SUCCESS;
5808 }
5809
5810 (*str)++;
f03698e6 5811 inst.error = _("register or shift expression expected");
b99bd4ef
NC
5812 return FAIL;
5813 }
5814}
5815
5816static int
5817fp_op2 (str)
5818 char ** str;
5819{
5820 skip_whitespace (* str);
5821
5822 if (fp_reg_required_here (str, 0) != FAIL)
5823 return SUCCESS;
5824 else
5825 {
5826 /* Immediate expression. */
5827 if (*((*str)++) == '#')
5828 {
5829 int i;
5830
5831 inst.error = NULL;
5832
5833 skip_whitespace (* str);
5834
5835 /* First try and match exact strings, this is to guarantee
5836 that some formats will work even for cross assembly. */
5837
5838 for (i = 0; fp_const[i]; i++)
5839 {
5840 if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
5841 {
5842 char *start = *str;
5843
5844 *str += strlen (fp_const[i]);
5845 if (is_end_of_line[(unsigned char) **str])
5846 {
5847 inst.instruction |= i + 8;
5848 return SUCCESS;
5849 }
5850 *str = start;
5851 }
5852 }
5853
5854 /* Just because we didn't get a match doesn't mean that the
5855 constant isn't valid, just that it is in a format that we
5856 don't automatically recognize. Try parsing it with
5857 the standard expression routines. */
5858 if ((i = my_get_float_expression (str)) >= 0)
5859 {
5860 inst.instruction |= i + 8;
5861 return SUCCESS;
5862 }
5863
f03698e6 5864 inst.error = _("invalid floating point immediate expression");
b99bd4ef
NC
5865 return FAIL;
5866 }
5867 inst.error =
f03698e6 5868 _("floating point register or immediate expression expected");
b99bd4ef
NC
5869 return FAIL;
5870 }
5871}
5872
5873static void
f2b7cb0a 5874do_arit (str)
b99bd4ef 5875 char * str;
b99bd4ef
NC
5876{
5877 skip_whitespace (str);
5878
5879 if (reg_required_here (&str, 12) == FAIL
5880 || skip_past_comma (&str) == FAIL
5881 || reg_required_here (&str, 16) == FAIL
5882 || skip_past_comma (&str) == FAIL
5883 || data_op2 (&str) == FAIL)
5884 {
5885 if (!inst.error)
5886 inst.error = BAD_ARGS;
5887 return;
5888 }
5889
b99bd4ef
NC
5890 end_of_line (str);
5891 return;
5892}
5893
5894static void
f2b7cb0a 5895do_adr (str)
b99bd4ef 5896 char * str;
b99bd4ef 5897{
90e4755a
RE
5898 /* This is a pseudo-op of the form "adr rd, label" to be converted
5899 into a relative address of the form "add rd, pc, #label-.-8". */
5900 skip_whitespace (str);
5901
5902 if (reg_required_here (&str, 12) == FAIL
5903 || skip_past_comma (&str) == FAIL
5904 || my_get_expression (&inst.reloc.exp, &str))
5905 {
5906 if (!inst.error)
5907 inst.error = BAD_ARGS;
5908 return;
5909 }
5910
5911 /* Frag hacking will turn this into a sub instruction if the offset turns
5912 out to be negative. */
5913 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
5914 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust. */
5915 inst.reloc.pc_rel = 1;
5916
5917 end_of_line (str);
5918}
5919
5920static void
f2b7cb0a 5921do_adrl (str)
90e4755a 5922 char * str;
90e4755a
RE
5923{
5924 /* This is a pseudo-op of the form "adrl rd, label" to be converted
5925 into a relative address of the form:
5926 add rd, pc, #low(label-.-8)"
5927 add rd, rd, #high(label-.-8)" */
5928
5929 skip_whitespace (str);
5930
5931 if (reg_required_here (&str, 12) == FAIL
5932 || skip_past_comma (&str) == FAIL
5933 || my_get_expression (&inst.reloc.exp, &str))
5934 {
5935 if (!inst.error)
5936 inst.error = BAD_ARGS;
5937
5938 return;
5939 }
5940
5941 end_of_line (str);
5942 /* Frag hacking will turn this into a sub instruction if the offset turns
5943 out to be negative. */
5944 inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
5945 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
5946 inst.reloc.pc_rel = 1;
5947 inst.size = INSN_SIZE * 2;
5948
5949 return;
5950}
5951
5952static void
f2b7cb0a 5953do_cmp (str)
90e4755a 5954 char * str;
90e4755a
RE
5955{
5956 skip_whitespace (str);
5957
5958 if (reg_required_here (&str, 16) == FAIL)
5959 {
5960 if (!inst.error)
5961 inst.error = BAD_ARGS;
5962 return;
5963 }
5964
5965 if (skip_past_comma (&str) == FAIL
5966 || data_op2 (&str) == FAIL)
5967 {
5968 if (!inst.error)
5969 inst.error = BAD_ARGS;
5970 return;
5971 }
5972
90e4755a
RE
5973 end_of_line (str);
5974 return;
5975}
5976
5977static void
f2b7cb0a 5978do_mov (str)
90e4755a 5979 char * str;
90e4755a
RE
5980{
5981 skip_whitespace (str);
5982
5983 if (reg_required_here (&str, 12) == FAIL)
5984 {
5985 if (!inst.error)
5986 inst.error = BAD_ARGS;
5987 return;
5988 }
5989
5990 if (skip_past_comma (&str) == FAIL
5991 || data_op2 (&str) == FAIL)
5992 {
5993 if (!inst.error)
5994 inst.error = BAD_ARGS;
5995 return;
5996 }
5997
90e4755a
RE
5998 end_of_line (str);
5999 return;
6000}
6001
6002static int
6003ldst_extend (str)
6004 char ** str;
6005{
6006 int add = INDEX_UP;
6007
6008 switch (**str)
6009 {
6010 case '#':
6011 case '$':
6012 (*str)++;
6013 if (my_get_expression (& inst.reloc.exp, str))
6014 return FAIL;
6015
6016 if (inst.reloc.exp.X_op == O_constant)
6017 {
6018 int value = inst.reloc.exp.X_add_number;
6019
6020 if (value < -4095 || value > 4095)
6021 {
6022 inst.error = _("address offset too large");
6023 return FAIL;
6024 }
6025
6026 if (value < 0)
6027 {
6028 value = -value;
6029 add = 0;
6030 }
6031
6032 inst.instruction |= add | value;
6033 }
6034 else
6035 {
6036 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6037 inst.reloc.pc_rel = 0;
6038 }
6039 return SUCCESS;
6040
6041 case '-':
6042 add = 0;
6043 /* Fall through. */
6044
6045 case '+':
6046 (*str)++;
6047 /* Fall through. */
6048
6049 default:
6050 if (reg_required_here (str, 0) == FAIL)
6051 return FAIL;
6052
6053 inst.instruction |= add | OFFSET_REG;
6054 if (skip_past_comma (str) == SUCCESS)
6055 return decode_shift (str, SHIFT_RESTRICT);
6056
6057 return SUCCESS;
6058 }
6059}
6060
6061static void
f2b7cb0a 6062do_ldst (str)
90e4755a 6063 char * str;
90e4755a
RE
6064{
6065 int pre_inc = 0;
6066 int conflict_reg;
6067 int value;
6068
b99bd4ef
NC
6069 skip_whitespace (str);
6070
90e4755a
RE
6071 if ((conflict_reg = reg_required_here (&str, 12)) == FAIL)
6072 {
6073 if (!inst.error)
6074 inst.error = BAD_ARGS;
6075 return;
6076 }
6077
6078 if (skip_past_comma (&str) == FAIL)
6079 {
f03698e6 6080 inst.error = _("address expected");
90e4755a
RE
6081 return;
6082 }
6083
90e4755a
RE
6084 if (*str == '[')
6085 {
6086 int reg;
6087
6088 str++;
6089
6090 skip_whitespace (str);
6091
6092 if ((reg = reg_required_here (&str, 16)) == FAIL)
6093 return;
6094
6095 /* Conflicts can occur on stores as well as loads. */
6096 conflict_reg = (conflict_reg == reg);
6097
6098 skip_whitespace (str);
6099
6100 if (*str == ']')
6101 {
6102 str ++;
6103
6104 if (skip_past_comma (&str) == SUCCESS)
6105 {
6106 /* [Rn],... (post inc) */
6107 if (ldst_extend (&str) == FAIL)
6108 return;
6109 if (conflict_reg)
6110 as_warn (_("%s register same as write-back base"),
6111 ((inst.instruction & LOAD_BIT)
6112 ? _("destination") : _("source")));
6113 }
6114 else
6115 {
6116 /* [Rn] */
6117 skip_whitespace (str);
6118
6119 if (*str == '!')
6120 {
6121 if (conflict_reg)
6122 as_warn (_("%s register same as write-back base"),
6123 ((inst.instruction & LOAD_BIT)
6124 ? _("destination") : _("source")));
6125 str++;
6126 inst.instruction |= WRITE_BACK;
6127 }
6128
6129 inst.instruction |= INDEX_UP;
6130 pre_inc = 1;
6131 }
6132 }
6133 else
6134 {
6135 /* [Rn,...] */
6136 if (skip_past_comma (&str) == FAIL)
6137 {
6138 inst.error = _("pre-indexed expression expected");
6139 return;
6140 }
6141
6142 pre_inc = 1;
6143 if (ldst_extend (&str) == FAIL)
6144 return;
6145
6146 skip_whitespace (str);
6147
6148 if (*str++ != ']')
6149 {
6150 inst.error = _("missing ]");
6151 return;
6152 }
6153
6154 skip_whitespace (str);
6155
6156 if (*str == '!')
6157 {
6158 if (conflict_reg)
6159 as_warn (_("%s register same as write-back base"),
6160 ((inst.instruction & LOAD_BIT)
6161 ? _("destination") : _("source")));
6162 str++;
6163 inst.instruction |= WRITE_BACK;
6164 }
6165 }
6166 }
6167 else if (*str == '=')
6168 {
f03698e6
RE
6169 if ((inst.instruction & LOAD_BIT) == 0)
6170 {
6171 inst.error = _("invalid pseudo operation");
6172 return;
6173 }
6174
90e4755a
RE
6175 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6176 str++;
6177
6178 skip_whitespace (str);
6179
6180 if (my_get_expression (&inst.reloc.exp, &str))
6181 return;
6182
6183 if (inst.reloc.exp.X_op != O_constant
6184 && inst.reloc.exp.X_op != O_symbol)
6185 {
f03698e6 6186 inst.error = _("constant expression expected");
90e4755a
RE
6187 return;
6188 }
6189
e28cd48c 6190 if (inst.reloc.exp.X_op == O_constant)
90e4755a 6191 {
e28cd48c
RE
6192 value = validate_immediate (inst.reloc.exp.X_add_number);
6193
6194 if (value != FAIL)
90e4755a 6195 {
e28cd48c
RE
6196 /* This can be done with a mov instruction. */
6197 inst.instruction &= LITERAL_MASK;
6198 inst.instruction |= (INST_IMMEDIATE
6199 | (OPCODE_MOV << DATA_OP_SHIFT));
6200 inst.instruction |= value & 0xfff;
6201 end_of_line (str);
90e4755a
RE
6202 return;
6203 }
b99bd4ef 6204
e28cd48c
RE
6205 value = validate_immediate (~inst.reloc.exp.X_add_number);
6206
6207 if (value != FAIL)
6208 {
6209 /* This can be done with a mvn instruction. */
6210 inst.instruction &= LITERAL_MASK;
6211 inst.instruction |= (INST_IMMEDIATE
6212 | (OPCODE_MVN << DATA_OP_SHIFT));
6213 inst.instruction |= value & 0xfff;
6214 end_of_line (str);
6215 return;
6216 }
90e4755a 6217 }
e28cd48c
RE
6218
6219 /* Insert into literal pool. */
6220 if (add_to_lit_pool () == FAIL)
6221 {
6222 if (!inst.error)
6223 inst.error = _("literal pool insertion failed");
6224 return;
6225 }
6226
6227 /* Change the instruction exp to point to the pool. */
6228 inst.reloc.type = BFD_RELOC_ARM_LITERAL;
6229 inst.reloc.pc_rel = 1;
6230 inst.instruction |= (REG_PC << 16);
6231 pre_inc = 1;
1cac9012
NC
6232 }
6233 else
6234 {
90e4755a
RE
6235 if (my_get_expression (&inst.reloc.exp, &str))
6236 return;
6237
6238 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6239#ifndef TE_WINCE
6240 /* PC rel adjust. */
6241 inst.reloc.exp.X_add_number -= 8;
6242#endif
1cac9012 6243 inst.reloc.pc_rel = 1;
90e4755a
RE
6244 inst.instruction |= (REG_PC << 16);
6245 pre_inc = 1;
b99bd4ef
NC
6246 }
6247
90e4755a 6248 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef 6249 end_of_line (str);
90e4755a 6250 return;
b99bd4ef
NC
6251}
6252
6253static void
f2b7cb0a 6254do_ldstt (str)
90e4755a 6255 char * str;
b99bd4ef 6256{
90e4755a
RE
6257 int conflict_reg;
6258
b99bd4ef
NC
6259 skip_whitespace (str);
6260
90e4755a 6261 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
b99bd4ef
NC
6262 {
6263 if (!inst.error)
6264 inst.error = BAD_ARGS;
6265 return;
6266 }
6267
90e4755a 6268 if (skip_past_comma (& str) == FAIL)
b99bd4ef 6269 {
f03698e6 6270 inst.error = _("address expected");
b99bd4ef
NC
6271 return;
6272 }
6273
90e4755a
RE
6274 if (*str == '[')
6275 {
6276 int reg;
b99bd4ef 6277
90e4755a 6278 str++;
b99bd4ef 6279
90e4755a 6280 skip_whitespace (str);
b99bd4ef 6281
90e4755a
RE
6282 if ((reg = reg_required_here (&str, 16)) == FAIL)
6283 return;
b99bd4ef 6284
90e4755a
RE
6285 /* ldrt/strt always use post-indexed addressing, so if the base is
6286 the same as Rd, we warn. */
6287 if (conflict_reg == reg)
6288 as_warn (_("%s register same as write-back base"),
6289 ((inst.instruction & LOAD_BIT)
6290 ? _("destination") : _("source")));
6291
6292 skip_whitespace (str);
6293
6294 if (*str == ']')
6295 {
6296 str ++;
6297
6298 if (skip_past_comma (&str) == SUCCESS)
6299 {
6300 /* [Rn],... (post inc) */
6301 if (ldst_extend (&str) == FAIL)
6302 return;
6303 }
6304 else
6305 {
6306 /* [Rn] */
6307 skip_whitespace (str);
6308
6309 /* Skip a write-back '!'. */
6310 if (*str == '!')
6311 str++;
6312
6313 inst.instruction |= INDEX_UP;
6314 }
6315 }
6316 else
6317 {
6318 inst.error = _("post-indexed expression expected");
6319 return;
6320 }
6321 }
6322 else
b99bd4ef 6323 {
90e4755a 6324 inst.error = _("post-indexed expression expected");
b99bd4ef
NC
6325 return;
6326 }
6327
b99bd4ef
NC
6328 end_of_line (str);
6329 return;
6330}
6331
6332static int
90e4755a 6333ldst_extend_v4 (str)
b99bd4ef 6334 char ** str;
b99bd4ef
NC
6335{
6336 int add = INDEX_UP;
6337
6338 switch (**str)
6339 {
6340 case '#':
6341 case '$':
6342 (*str)++;
6343 if (my_get_expression (& inst.reloc.exp, str))
6344 return FAIL;
6345
6346 if (inst.reloc.exp.X_op == O_constant)
6347 {
6348 int value = inst.reloc.exp.X_add_number;
6349
90e4755a 6350 if (value < -255 || value > 255)
b99bd4ef
NC
6351 {
6352 inst.error = _("address offset too large");
6353 return FAIL;
6354 }
6355
6356 if (value < 0)
6357 {
6358 value = -value;
6359 add = 0;
6360 }
6361
6362 /* Halfword and signextension instructions have the
6363 immediate value split across bits 11..8 and bits 3..0. */
90e4755a
RE
6364 inst.instruction |= (add | HWOFFSET_IMM
6365 | ((value >> 4) << 8) | (value & 0xF));
b99bd4ef
NC
6366 }
6367 else
6368 {
90e4755a
RE
6369 inst.instruction |= HWOFFSET_IMM;
6370 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
b99bd4ef
NC
6371 inst.reloc.pc_rel = 0;
6372 }
6373 return SUCCESS;
6374
6375 case '-':
6376 add = 0;
6377 /* Fall through. */
6378
6379 case '+':
6380 (*str)++;
6381 /* Fall through. */
6382
6383 default:
6384 if (reg_required_here (str, 0) == FAIL)
6385 return FAIL;
6386
90e4755a 6387 inst.instruction |= add;
b99bd4ef
NC
6388 return SUCCESS;
6389 }
6390}
6391
90e4755a 6392/* Halfword and signed-byte load/store operations. */
b99bd4ef 6393static void
f2b7cb0a 6394do_ldstv4 (str)
b99bd4ef 6395 char * str;
b99bd4ef 6396{
b99bd4ef
NC
6397 int pre_inc = 0;
6398 int conflict_reg;
6399 int value;
6400
b99bd4ef
NC
6401 skip_whitespace (str);
6402
6403 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
6404 {
6405 if (!inst.error)
6406 inst.error = BAD_ARGS;
6407 return;
6408 }
6409
6410 if (skip_past_comma (& str) == FAIL)
6411 {
f03698e6 6412 inst.error = _("address expected");
b99bd4ef
NC
6413 return;
6414 }
6415
6416 if (*str == '[')
6417 {
6418 int reg;
6419
6420 str++;
6421
6422 skip_whitespace (str);
6423
6424 if ((reg = reg_required_here (&str, 16)) == FAIL)
6425 return;
6426
6427 /* Conflicts can occur on stores as well as loads. */
6428 conflict_reg = (conflict_reg == reg);
6429
6430 skip_whitespace (str);
6431
6432 if (*str == ']')
6433 {
6434 str ++;
6435
6436 if (skip_past_comma (&str) == SUCCESS)
6437 {
6438 /* [Rn],... (post inc) */
90e4755a 6439 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6440 return;
6441 if (conflict_reg)
90e4755a
RE
6442 as_warn (_("%s register same as write-back base"),
6443 ((inst.instruction & LOAD_BIT)
6444 ? _("destination") : _("source")));
b99bd4ef
NC
6445 }
6446 else
6447 {
6448 /* [Rn] */
90e4755a 6449 inst.instruction |= HWOFFSET_IMM;
b99bd4ef
NC
6450
6451 skip_whitespace (str);
6452
6453 if (*str == '!')
6454 {
6455 if (conflict_reg)
6456 as_warn (_("%s register same as write-back base"),
6457 ((inst.instruction & LOAD_BIT)
6458 ? _("destination") : _("source")));
6459 str++;
6460 inst.instruction |= WRITE_BACK;
6461 }
6462
90e4755a
RE
6463 inst.instruction |= INDEX_UP;
6464 pre_inc = 1;
b99bd4ef
NC
6465 }
6466 }
6467 else
6468 {
6469 /* [Rn,...] */
6470 if (skip_past_comma (&str) == FAIL)
6471 {
6472 inst.error = _("pre-indexed expression expected");
6473 return;
6474 }
6475
6476 pre_inc = 1;
90e4755a 6477 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6478 return;
6479
6480 skip_whitespace (str);
6481
6482 if (*str++ != ']')
6483 {
6484 inst.error = _("missing ]");
6485 return;
6486 }
6487
6488 skip_whitespace (str);
6489
6490 if (*str == '!')
6491 {
6492 if (conflict_reg)
6493 as_warn (_("%s register same as write-back base"),
6494 ((inst.instruction & LOAD_BIT)
6495 ? _("destination") : _("source")));
6496 str++;
6497 inst.instruction |= WRITE_BACK;
6498 }
6499 }
6500 }
6501 else if (*str == '=')
6502 {
f03698e6
RE
6503 if ((inst.instruction & LOAD_BIT) == 0)
6504 {
6505 inst.error = _("invalid pseudo operation");
6506 return;
6507 }
6508
90e4755a 6509 /* XXX Does this work correctly for half-word/byte ops? */
b99bd4ef
NC
6510 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6511 str++;
6512
6513 skip_whitespace (str);
6514
6515 if (my_get_expression (&inst.reloc.exp, &str))
6516 return;
6517
6518 if (inst.reloc.exp.X_op != O_constant
6519 && inst.reloc.exp.X_op != O_symbol)
6520 {
f03698e6 6521 inst.error = _("constant expression expected");
b99bd4ef
NC
6522 return;
6523 }
6524
d8273442 6525 if (inst.reloc.exp.X_op == O_constant)
b99bd4ef 6526 {
d8273442
NC
6527 value = validate_immediate (inst.reloc.exp.X_add_number);
6528
6529 if (value != FAIL)
b99bd4ef 6530 {
d8273442
NC
6531 /* This can be done with a mov instruction. */
6532 inst.instruction &= LITERAL_MASK;
6533 inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
90e4755a 6534 inst.instruction |= value & 0xfff;
d8273442 6535 end_of_line (str);
b99bd4ef
NC
6536 return;
6537 }
cc8a6dd0 6538
d8273442 6539 value = validate_immediate (~ inst.reloc.exp.X_add_number);
b99bd4ef 6540
d8273442 6541 if (value != FAIL)
b99bd4ef 6542 {
d8273442
NC
6543 /* This can be done with a mvn instruction. */
6544 inst.instruction &= LITERAL_MASK;
6545 inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
90e4755a 6546 inst.instruction |= value & 0xfff;
d8273442
NC
6547 end_of_line (str);
6548 return;
b99bd4ef 6549 }
b99bd4ef 6550 }
d8273442
NC
6551
6552 /* Insert into literal pool. */
6553 if (add_to_lit_pool () == FAIL)
6554 {
6555 if (!inst.error)
6556 inst.error = _("literal pool insertion failed");
6557 return;
6558 }
6559
6560 /* Change the instruction exp to point to the pool. */
90e4755a
RE
6561 inst.instruction |= HWOFFSET_IMM;
6562 inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
d8273442
NC
6563 inst.reloc.pc_rel = 1;
6564 inst.instruction |= (REG_PC << 16);
6565 pre_inc = 1;
b99bd4ef
NC
6566 }
6567 else
6568 {
6569 if (my_get_expression (&inst.reloc.exp, &str))
6570 return;
6571
90e4755a
RE
6572 inst.instruction |= HWOFFSET_IMM;
6573 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
b99bd4ef
NC
6574#ifndef TE_WINCE
6575 /* PC rel adjust. */
6576 inst.reloc.exp.X_add_number -= 8;
6577#endif
6578 inst.reloc.pc_rel = 1;
6579 inst.instruction |= (REG_PC << 16);
6580 pre_inc = 1;
6581 }
6582
90e4755a 6583 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef
NC
6584 end_of_line (str);
6585 return;
6586}
6587
6588static long
6589reg_list (strp)
6590 char ** strp;
6591{
6592 char * str = * strp;
6593 long range = 0;
6594 int another_range;
6595
6596 /* We come back here if we get ranges concatenated by '+' or '|'. */
6597 do
6598 {
6599 another_range = 0;
6600
6601 if (*str == '{')
6602 {
6603 int in_range = 0;
6604 int cur_reg = -1;
6605
6606 str++;
6607 do
6608 {
6609 int reg;
6610
6611 skip_whitespace (str);
6612
6613 if ((reg = reg_required_here (& str, -1)) == FAIL)
6614 return FAIL;
6615
6616 if (in_range)
6617 {
6618 int i;
6619
6620 if (reg <= cur_reg)
6621 {
f03698e6 6622 inst.error = _("bad range in register list");
b99bd4ef
NC
6623 return FAIL;
6624 }
6625
6626 for (i = cur_reg + 1; i < reg; i++)
6627 {
6628 if (range & (1 << i))
6629 as_tsktsk
f03698e6 6630 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6631 i);
6632 else
6633 range |= 1 << i;
6634 }
6635 in_range = 0;
6636 }
6637
6638 if (range & (1 << reg))
f03698e6 6639 as_tsktsk (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6640 reg);
6641 else if (reg <= cur_reg)
f03698e6 6642 as_tsktsk (_("Warning: register range not in ascending order"));
b99bd4ef
NC
6643
6644 range |= 1 << reg;
6645 cur_reg = reg;
6646 }
6647 while (skip_past_comma (&str) != FAIL
6648 || (in_range = 1, *str++ == '-'));
6649 str--;
6650 skip_whitespace (str);
6651
6652 if (*str++ != '}')
6653 {
f03698e6 6654 inst.error = _("missing `}'");
b99bd4ef
NC
6655 return FAIL;
6656 }
6657 }
6658 else
6659 {
6660 expressionS expr;
6661
6662 if (my_get_expression (&expr, &str))
6663 return FAIL;
6664
6665 if (expr.X_op == O_constant)
6666 {
6667 if (expr.X_add_number
6668 != (expr.X_add_number & 0x0000ffff))
6669 {
6670 inst.error = _("invalid register mask");
6671 return FAIL;
6672 }
6673
6674 if ((range & expr.X_add_number) != 0)
6675 {
6676 int regno = range & expr.X_add_number;
6677
6678 regno &= -regno;
6679 regno = (1 << regno) - 1;
6680 as_tsktsk
f03698e6 6681 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6682 regno);
6683 }
6684
6685 range |= expr.X_add_number;
6686 }
6687 else
6688 {
6689 if (inst.reloc.type != 0)
6690 {
6691 inst.error = _("expression too complex");
6692 return FAIL;
6693 }
6694
6695 memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
6696 inst.reloc.type = BFD_RELOC_ARM_MULTI;
6697 inst.reloc.pc_rel = 0;
6698 }
6699 }
6700
6701 skip_whitespace (str);
6702
6703 if (*str == '|' || *str == '+')
6704 {
6705 str++;
6706 another_range = 1;
6707 }
6708 }
6709 while (another_range);
6710
6711 *strp = str;
6712 return range;
6713}
6714
6715static void
f2b7cb0a 6716do_ldmstm (str)
b99bd4ef 6717 char * str;
b99bd4ef
NC
6718{
6719 int base_reg;
6720 long range;
6721
6722 skip_whitespace (str);
6723
6724 if ((base_reg = reg_required_here (&str, 16)) == FAIL)
6725 return;
6726
6727 if (base_reg == REG_PC)
6728 {
6729 inst.error = _("r15 not allowed as base register");
6730 return;
6731 }
6732
6733 skip_whitespace (str);
6734
6735 if (*str == '!')
6736 {
90e4755a 6737 inst.instruction |= WRITE_BACK;
b99bd4ef
NC
6738 str++;
6739 }
6740
6741 if (skip_past_comma (&str) == FAIL
6742 || (range = reg_list (&str)) == FAIL)
6743 {
6744 if (! inst.error)
6745 inst.error = BAD_ARGS;
6746 return;
6747 }
6748
6749 if (*str == '^')
6750 {
6751 str++;
90e4755a 6752 inst.instruction |= LDM_TYPE_2_OR_3;
b99bd4ef
NC
6753 }
6754
6189168b
NC
6755 if (inst.instruction & WRITE_BACK)
6756 {
6757 /* Check for unpredictable uses of writeback. */
6758 if (inst.instruction & LOAD_BIT)
6759 {
6760 /* Not allowed in LDM type 2. */
6761 if ((inst.instruction & LDM_TYPE_2_OR_3)
6762 && ((range & (1 << REG_PC)) == 0))
6763 as_warn (_("writeback of base register is UNPREDICTABLE"));
6764 /* Only allowed if base reg not in list for other types. */
6765 else if (range & (1 << base_reg))
6766 as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
6767 }
6768 else /* STM. */
6769 {
6770 /* Not allowed for type 2. */
6771 if (inst.instruction & LDM_TYPE_2_OR_3)
6772 as_warn (_("writeback of base register is UNPREDICTABLE"));
6773 /* Only allowed if base reg not in list, or first in list. */
6774 else if ((range & (1 << base_reg))
6775 && (range & ((1 << base_reg) - 1)))
6776 as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
6777 }
6778 }
61b5f74b 6779
f2b7cb0a 6780 inst.instruction |= range;
b99bd4ef
NC
6781 end_of_line (str);
6782 return;
6783}
6784
6785static void
f2b7cb0a 6786do_swi (str)
b99bd4ef 6787 char * str;
b99bd4ef
NC
6788{
6789 skip_whitespace (str);
6790
6791 /* Allow optional leading '#'. */
6792 if (is_immediate_prefix (*str))
6793 str++;
6794
6795 if (my_get_expression (& inst.reloc.exp, & str))
6796 return;
6797
6798 inst.reloc.type = BFD_RELOC_ARM_SWI;
6799 inst.reloc.pc_rel = 0;
b99bd4ef
NC
6800 end_of_line (str);
6801
6802 return;
6803}
6804
6805static void
f2b7cb0a 6806do_swap (str)
b99bd4ef 6807 char * str;
b99bd4ef
NC
6808{
6809 int reg;
6810
6811 skip_whitespace (str);
6812
6813 if ((reg = reg_required_here (&str, 12)) == FAIL)
6814 return;
6815
6816 if (reg == REG_PC)
6817 {
6818 inst.error = _("r15 not allowed in swap");
6819 return;
6820 }
6821
6822 if (skip_past_comma (&str) == FAIL
6823 || (reg = reg_required_here (&str, 0)) == FAIL)
6824 {
6825 if (!inst.error)
6826 inst.error = BAD_ARGS;
6827 return;
6828 }
6829
6830 if (reg == REG_PC)
6831 {
6832 inst.error = _("r15 not allowed in swap");
6833 return;
6834 }
6835
6836 if (skip_past_comma (&str) == FAIL
6837 || *str++ != '[')
6838 {
6839 inst.error = BAD_ARGS;
6840 return;
6841 }
6842
6843 skip_whitespace (str);
6844
6845 if ((reg = reg_required_here (&str, 16)) == FAIL)
6846 return;
6847
6848 if (reg == REG_PC)
6849 {
6850 inst.error = BAD_PC;
6851 return;
6852 }
6853
6854 skip_whitespace (str);
6855
6856 if (*str++ != ']')
6857 {
6858 inst.error = _("missing ]");
6859 return;
6860 }
6861
b99bd4ef
NC
6862 end_of_line (str);
6863 return;
6864}
6865
6866static void
f2b7cb0a 6867do_branch (str)
b99bd4ef 6868 char * str;
b99bd4ef
NC
6869{
6870 if (my_get_expression (&inst.reloc.exp, &str))
6871 return;
6872
6873#ifdef OBJ_ELF
6874 {
6875 char * save_in;
6876
6877 /* ScottB: February 5, 1998 - Check to see of PLT32 reloc
6878 required for the instruction. */
6879
6880 /* arm_parse_reloc () works on input_line_pointer.
6881 We actually want to parse the operands to the branch instruction
6882 passed in 'str'. Save the input pointer and restore it later. */
6883 save_in = input_line_pointer;
6884 input_line_pointer = str;
6885 if (inst.reloc.exp.X_op == O_symbol
6886 && *str == '('
6887 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
6888 {
6889 inst.reloc.type = BFD_RELOC_ARM_PLT32;
6890 inst.reloc.pc_rel = 0;
6891 /* Modify str to point to after parsed operands, otherwise
6892 end_of_line() will complain about the (PLT) left in str. */
6893 str = input_line_pointer;
6894 }
6895 else
6896 {
6897 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
6898 inst.reloc.pc_rel = 1;
6899 }
6900 input_line_pointer = save_in;
6901 }
6902#else
6903 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
6904 inst.reloc.pc_rel = 1;
6905#endif /* OBJ_ELF */
6906
6907 end_of_line (str);
6908 return;
6909}
6910
6911static void
f2b7cb0a 6912do_bx (str)
b99bd4ef 6913 char * str;
b99bd4ef
NC
6914{
6915 int reg;
6916
6917 skip_whitespace (str);
6918
6919 if ((reg = reg_required_here (&str, 0)) == FAIL)
6920 {
6921 inst.error = BAD_ARGS;
6922 return;
6923 }
6924
6925 /* Note - it is not illegal to do a "bx pc". Useless, but not illegal. */
6926 if (reg == REG_PC)
f03698e6 6927 as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
b99bd4ef
NC
6928
6929 end_of_line (str);
6930}
6931
6932static void
f2b7cb0a 6933do_cdp (str)
b99bd4ef 6934 char * str;
b99bd4ef
NC
6935{
6936 /* Co-processor data operation.
6937 Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */
6938 skip_whitespace (str);
6939
6940 if (co_proc_number (&str) == FAIL)
6941 {
6942 if (!inst.error)
6943 inst.error = BAD_ARGS;
6944 return;
6945 }
6946
6947 if (skip_past_comma (&str) == FAIL
6948 || cp_opc_expr (&str, 20,4) == FAIL)
6949 {
6950 if (!inst.error)
6951 inst.error = BAD_ARGS;
6952 return;
6953 }
6954
6955 if (skip_past_comma (&str) == FAIL
6956 || cp_reg_required_here (&str, 12) == FAIL)
6957 {
6958 if (!inst.error)
6959 inst.error = BAD_ARGS;
6960 return;
6961 }
6962
6963 if (skip_past_comma (&str) == FAIL
6964 || cp_reg_required_here (&str, 16) == FAIL)
6965 {
6966 if (!inst.error)
6967 inst.error = BAD_ARGS;
6968 return;
6969 }
6970
6971 if (skip_past_comma (&str) == FAIL
6972 || cp_reg_required_here (&str, 0) == FAIL)
6973 {
6974 if (!inst.error)
6975 inst.error = BAD_ARGS;
6976 return;
6977 }
6978
6979 if (skip_past_comma (&str) == SUCCESS)
6980 {
6981 if (cp_opc_expr (&str, 5, 3) == FAIL)
6982 {
6983 if (!inst.error)
6984 inst.error = BAD_ARGS;
6985 return;
6986 }
6987 }
6988
6989 end_of_line (str);
6990 return;
6991}
6992
6993static void
f2b7cb0a 6994do_lstc (str)
b99bd4ef 6995 char * str;
b99bd4ef
NC
6996{
6997 /* Co-processor register load/store.
6998 Format: <LDC|STC{cond}[L] CP#,CRd,<address> */
6999
7000 skip_whitespace (str);
7001
7002 if (co_proc_number (&str) == FAIL)
7003 {
7004 if (!inst.error)
7005 inst.error = BAD_ARGS;
7006 return;
7007 }
7008
7009 if (skip_past_comma (&str) == FAIL
7010 || cp_reg_required_here (&str, 12) == FAIL)
7011 {
7012 if (!inst.error)
7013 inst.error = BAD_ARGS;
7014 return;
7015 }
7016
7017 if (skip_past_comma (&str) == FAIL
bfae80f2 7018 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7019 {
7020 if (! inst.error)
7021 inst.error = BAD_ARGS;
7022 return;
7023 }
7024
b99bd4ef
NC
7025 end_of_line (str);
7026 return;
7027}
7028
7029static void
f2b7cb0a 7030do_co_reg (str)
b99bd4ef 7031 char * str;
b99bd4ef
NC
7032{
7033 /* Co-processor register transfer.
7034 Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */
7035
7036 skip_whitespace (str);
7037
7038 if (co_proc_number (&str) == FAIL)
7039 {
7040 if (!inst.error)
7041 inst.error = BAD_ARGS;
7042 return;
7043 }
7044
7045 if (skip_past_comma (&str) == FAIL
7046 || cp_opc_expr (&str, 21, 3) == FAIL)
7047 {
7048 if (!inst.error)
7049 inst.error = BAD_ARGS;
7050 return;
7051 }
7052
7053 if (skip_past_comma (&str) == FAIL
7054 || reg_required_here (&str, 12) == FAIL)
7055 {
7056 if (!inst.error)
7057 inst.error = BAD_ARGS;
7058 return;
7059 }
7060
7061 if (skip_past_comma (&str) == FAIL
7062 || cp_reg_required_here (&str, 16) == FAIL)
7063 {
7064 if (!inst.error)
7065 inst.error = BAD_ARGS;
7066 return;
7067 }
7068
7069 if (skip_past_comma (&str) == FAIL
7070 || cp_reg_required_here (&str, 0) == FAIL)
7071 {
7072 if (!inst.error)
7073 inst.error = BAD_ARGS;
7074 return;
7075 }
7076
7077 if (skip_past_comma (&str) == SUCCESS)
7078 {
7079 if (cp_opc_expr (&str, 5, 3) == FAIL)
7080 {
7081 if (!inst.error)
7082 inst.error = BAD_ARGS;
7083 return;
7084 }
7085 }
b99bd4ef
NC
7086
7087 end_of_line (str);
7088 return;
7089}
7090
7091static void
f2b7cb0a 7092do_fpa_ctrl (str)
b99bd4ef 7093 char * str;
b99bd4ef
NC
7094{
7095 /* FP control registers.
7096 Format: <WFS|RFS|WFC|RFC>{cond} Rn */
7097
7098 skip_whitespace (str);
7099
7100 if (reg_required_here (&str, 12) == FAIL)
7101 {
7102 if (!inst.error)
7103 inst.error = BAD_ARGS;
7104 return;
7105 }
7106
7107 end_of_line (str);
7108 return;
7109}
7110
7111static void
f2b7cb0a 7112do_fpa_ldst (str)
b99bd4ef 7113 char * str;
b99bd4ef
NC
7114{
7115 skip_whitespace (str);
7116
b99bd4ef
NC
7117 if (fp_reg_required_here (&str, 12) == FAIL)
7118 {
7119 if (!inst.error)
7120 inst.error = BAD_ARGS;
7121 return;
7122 }
7123
7124 if (skip_past_comma (&str) == FAIL
bfae80f2 7125 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7126 {
7127 if (!inst.error)
7128 inst.error = BAD_ARGS;
7129 return;
7130 }
7131
7132 end_of_line (str);
7133}
7134
7135static void
f2b7cb0a 7136do_fpa_ldmstm (str)
b99bd4ef 7137 char * str;
b99bd4ef
NC
7138{
7139 int num_regs;
7140
7141 skip_whitespace (str);
7142
7143 if (fp_reg_required_here (&str, 12) == FAIL)
7144 {
7145 if (! inst.error)
7146 inst.error = BAD_ARGS;
7147 return;
7148 }
7149
7150 /* Get Number of registers to transfer. */
7151 if (skip_past_comma (&str) == FAIL
7152 || my_get_expression (&inst.reloc.exp, &str))
7153 {
7154 if (! inst.error)
7155 inst.error = _("constant expression expected");
7156 return;
7157 }
7158
7159 if (inst.reloc.exp.X_op != O_constant)
7160 {
f03698e6 7161 inst.error = _("constant value required for number of registers");
b99bd4ef
NC
7162 return;
7163 }
7164
7165 num_regs = inst.reloc.exp.X_add_number;
7166
7167 if (num_regs < 1 || num_regs > 4)
7168 {
7169 inst.error = _("number of registers must be in the range [1:4]");
7170 return;
7171 }
7172
7173 switch (num_regs)
7174 {
7175 case 1:
7176 inst.instruction |= CP_T_X;
7177 break;
7178 case 2:
7179 inst.instruction |= CP_T_Y;
7180 break;
7181 case 3:
7182 inst.instruction |= CP_T_Y | CP_T_X;
7183 break;
7184 case 4:
7185 break;
7186 default:
7187 abort ();
7188 }
7189
e28cd48c 7190 if (inst.instruction & (CP_T_Pre | CP_T_UD)) /* ea/fd format. */
b99bd4ef
NC
7191 {
7192 int reg;
7193 int write_back;
7194 int offset;
7195
7196 /* The instruction specified "ea" or "fd", so we can only accept
7197 [Rn]{!}. The instruction does not really support stacking or
7198 unstacking, so we have to emulate these by setting appropriate
7199 bits and offsets. */
7200 if (skip_past_comma (&str) == FAIL
7201 || *str != '[')
7202 {
7203 if (! inst.error)
7204 inst.error = BAD_ARGS;
7205 return;
7206 }
7207
7208 str++;
7209 skip_whitespace (str);
7210
7211 if ((reg = reg_required_here (&str, 16)) == FAIL)
7212 return;
7213
7214 skip_whitespace (str);
7215
7216 if (*str != ']')
7217 {
7218 inst.error = BAD_ARGS;
7219 return;
7220 }
7221
7222 str++;
7223 if (*str == '!')
7224 {
7225 write_back = 1;
7226 str++;
7227 if (reg == REG_PC)
7228 {
7229 inst.error =
f03698e6 7230 _("r15 not allowed as base register with write-back");
b99bd4ef
NC
7231 return;
7232 }
7233 }
7234 else
7235 write_back = 0;
7236
90e4755a 7237 if (inst.instruction & CP_T_Pre)
b99bd4ef
NC
7238 {
7239 /* Pre-decrement. */
7240 offset = 3 * num_regs;
7241 if (write_back)
90e4755a 7242 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7243 }
7244 else
7245 {
7246 /* Post-increment. */
7247 if (write_back)
7248 {
90e4755a 7249 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7250 offset = 3 * num_regs;
7251 }
7252 else
7253 {
7254 /* No write-back, so convert this into a standard pre-increment
7255 instruction -- aesthetically more pleasing. */
90e4755a 7256 inst.instruction |= CP_T_Pre | CP_T_UD;
b99bd4ef
NC
7257 offset = 0;
7258 }
7259 }
7260
f2b7cb0a 7261 inst.instruction |= offset;
b99bd4ef
NC
7262 }
7263 else if (skip_past_comma (&str) == FAIL
bfae80f2 7264 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7265 {
7266 if (! inst.error)
7267 inst.error = BAD_ARGS;
7268 return;
7269 }
7270
7271 end_of_line (str);
7272}
7273
7274static void
f2b7cb0a 7275do_fpa_dyadic (str)
b99bd4ef 7276 char * str;
b99bd4ef
NC
7277{
7278 skip_whitespace (str);
7279
b99bd4ef
NC
7280 if (fp_reg_required_here (&str, 12) == FAIL)
7281 {
7282 if (! inst.error)
7283 inst.error = BAD_ARGS;
7284 return;
7285 }
7286
7287 if (skip_past_comma (&str) == FAIL
7288 || fp_reg_required_here (&str, 16) == FAIL)
7289 {
7290 if (! inst.error)
7291 inst.error = BAD_ARGS;
7292 return;
7293 }
7294
7295 if (skip_past_comma (&str) == FAIL
7296 || fp_op2 (&str) == FAIL)
7297 {
7298 if (! inst.error)
7299 inst.error = BAD_ARGS;
7300 return;
7301 }
7302
b99bd4ef
NC
7303 end_of_line (str);
7304 return;
7305}
7306
7307static void
f2b7cb0a 7308do_fpa_monadic (str)
b99bd4ef 7309 char * str;
b99bd4ef
NC
7310{
7311 skip_whitespace (str);
7312
b99bd4ef
NC
7313 if (fp_reg_required_here (&str, 12) == FAIL)
7314 {
7315 if (! inst.error)
7316 inst.error = BAD_ARGS;
7317 return;
7318 }
7319
7320 if (skip_past_comma (&str) == FAIL
7321 || fp_op2 (&str) == FAIL)
7322 {
7323 if (! inst.error)
7324 inst.error = BAD_ARGS;
7325 return;
7326 }
7327
b99bd4ef
NC
7328 end_of_line (str);
7329 return;
7330}
7331
7332static void
f2b7cb0a 7333do_fpa_cmp (str)
b99bd4ef 7334 char * str;
b99bd4ef
NC
7335{
7336 skip_whitespace (str);
7337
7338 if (fp_reg_required_here (&str, 16) == FAIL)
7339 {
7340 if (! inst.error)
7341 inst.error = BAD_ARGS;
7342 return;
7343 }
7344
7345 if (skip_past_comma (&str) == FAIL
7346 || fp_op2 (&str) == FAIL)
7347 {
7348 if (! inst.error)
7349 inst.error = BAD_ARGS;
7350 return;
7351 }
7352
b99bd4ef
NC
7353 end_of_line (str);
7354 return;
7355}
7356
7357static void
f2b7cb0a 7358do_fpa_from_reg (str)
b99bd4ef 7359 char * str;
b99bd4ef
NC
7360{
7361 skip_whitespace (str);
7362
b99bd4ef
NC
7363 if (fp_reg_required_here (&str, 16) == FAIL)
7364 {
7365 if (! inst.error)
7366 inst.error = BAD_ARGS;
7367 return;
7368 }
7369
7370 if (skip_past_comma (&str) == FAIL
7371 || reg_required_here (&str, 12) == FAIL)
7372 {
7373 if (! inst.error)
7374 inst.error = BAD_ARGS;
7375 return;
7376 }
7377
b99bd4ef
NC
7378 end_of_line (str);
7379 return;
7380}
7381
7382static void
f2b7cb0a 7383do_fpa_to_reg (str)
b99bd4ef 7384 char * str;
b99bd4ef
NC
7385{
7386 skip_whitespace (str);
7387
7388 if (reg_required_here (&str, 12) == FAIL)
7389 return;
7390
7391 if (skip_past_comma (&str) == FAIL
7392 || fp_reg_required_here (&str, 0) == FAIL)
7393 {
7394 if (! inst.error)
7395 inst.error = BAD_ARGS;
7396 return;
7397 }
7398
b99bd4ef
NC
7399 end_of_line (str);
7400 return;
7401}
7402
b99bd4ef 7403static int
bfae80f2
RE
7404vfp_sp_reg_required_here (str, pos)
7405 char **str;
7406 enum vfp_sp_reg_pos pos;
b99bd4ef 7407{
bfae80f2
RE
7408 int reg;
7409 char *start = *str;
b99bd4ef 7410
bfae80f2 7411 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab)) != FAIL)
b99bd4ef 7412 {
bfae80f2 7413 switch (pos)
b99bd4ef 7414 {
bfae80f2
RE
7415 case VFP_REG_Sd:
7416 inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
7417 break;
7418
7419 case VFP_REG_Sn:
7420 inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
7421 break;
7422
7423 case VFP_REG_Sm:
7424 inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
7425 break;
7426
7427 default:
7428 abort ();
b99bd4ef 7429 }
bfae80f2
RE
7430 return reg;
7431 }
b99bd4ef 7432
bfae80f2
RE
7433 /* In the few cases where we might be able to accept something else
7434 this error can be overridden. */
7435 inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
7436
7437 /* Restore the start point. */
7438 *str = start;
7439 return FAIL;
7440}
7441
7442static int
7443vfp_dp_reg_required_here (str, pos)
7444 char **str;
f201ccb3 7445 enum vfp_dp_reg_pos pos;
bfae80f2
RE
7446{
7447 int reg;
7448 char *start = *str;
7449
7450 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL)
7451 {
7452 switch (pos)
b99bd4ef 7453 {
bfae80f2
RE
7454 case VFP_REG_Dd:
7455 inst.instruction |= reg << 12;
7456 break;
b99bd4ef 7457
bfae80f2
RE
7458 case VFP_REG_Dn:
7459 inst.instruction |= reg << 16;
7460 break;
7461
7462 case VFP_REG_Dm:
7463 inst.instruction |= reg << 0;
7464 break;
7465
7466 default:
7467 abort ();
7468 }
7469 return reg;
b99bd4ef
NC
7470 }
7471
bfae80f2
RE
7472 /* In the few cases where we might be able to accept something else
7473 this error can be overridden. */
7474 inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
b99bd4ef 7475
bfae80f2
RE
7476 /* Restore the start point. */
7477 *str = start;
7478 return FAIL;
7479}
b99bd4ef
NC
7480
7481static void
bfae80f2
RE
7482do_vfp_sp_monadic (str)
7483 char *str;
b99bd4ef 7484{
b99bd4ef
NC
7485 skip_whitespace (str);
7486
bfae80f2
RE
7487 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7488 return;
7489
7490 if (skip_past_comma (&str) == FAIL
7491 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef
NC
7492 {
7493 if (! inst.error)
7494 inst.error = BAD_ARGS;
7495 return;
7496 }
7497
bfae80f2
RE
7498 end_of_line (str);
7499 return;
7500}
7501
7502static void
7503do_vfp_dp_monadic (str)
7504 char *str;
7505{
7506 skip_whitespace (str);
7507
7508 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7509 return;
7510
7511 if (skip_past_comma (&str) == FAIL
7512 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
b99bd4ef 7513 {
bfae80f2
RE
7514 if (! inst.error)
7515 inst.error = BAD_ARGS;
7516 return;
b99bd4ef 7517 }
b99bd4ef 7518
bfae80f2
RE
7519 end_of_line (str);
7520 return;
7521}
b99bd4ef 7522
bfae80f2
RE
7523static void
7524do_vfp_sp_dyadic (str)
7525 char *str;
7526{
7527 skip_whitespace (str);
b99bd4ef 7528
bfae80f2
RE
7529 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7530 return;
b99bd4ef 7531
bfae80f2
RE
7532 if (skip_past_comma (&str) == FAIL
7533 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL
7534 || skip_past_comma (&str) == FAIL
7535 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef 7536 {
bfae80f2
RE
7537 if (! inst.error)
7538 inst.error = BAD_ARGS;
7539 return;
7540 }
b99bd4ef 7541
bfae80f2
RE
7542 end_of_line (str);
7543 return;
7544}
b99bd4ef 7545
bfae80f2
RE
7546static void
7547do_vfp_dp_dyadic (str)
7548 char *str;
7549{
7550 skip_whitespace (str);
b99bd4ef 7551
bfae80f2
RE
7552 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7553 return;
b99bd4ef 7554
bfae80f2
RE
7555 if (skip_past_comma (&str) == FAIL
7556 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL
7557 || skip_past_comma (&str) == FAIL
7558 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7559 {
7560 if (! inst.error)
7561 inst.error = BAD_ARGS;
7562 return;
7563 }
b99bd4ef 7564
bfae80f2
RE
7565 end_of_line (str);
7566 return;
7567}
b99bd4ef 7568
bfae80f2
RE
7569static void
7570do_vfp_reg_from_sp (str)
7571 char *str;
7572{
7573 skip_whitespace (str);
7574
7575 if (reg_required_here (&str, 12) == FAIL)
7576 return;
7577
7578 if (skip_past_comma (&str) == FAIL
7579 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7580 {
7581 if (! inst.error)
7582 inst.error = BAD_ARGS;
7583 return;
7584 }
7585
7586 end_of_line (str);
7587 return;
7588}
7589
7590static void
7591do_vfp_sp_reg2 (str)
7592 char *str;
7593{
7594 skip_whitespace (str);
7595
7596 if (reg_required_here (&str, 12) == FAIL)
7597 return;
7598
7599 if (skip_past_comma (&str) == FAIL
7600 || reg_required_here (&str, 16) == FAIL
7601 || skip_past_comma (&str) == FAIL)
7602 {
7603 if (! inst.error)
7604 inst.error = BAD_ARGS;
7605 return;
7606 }
7607
7608 /* We require exactly two consecutive SP registers. */
7609 if (vfp_sp_reg_list (&str, VFP_REG_Sm) != 2)
7610 {
7611 if (! inst.error)
7612 inst.error = _("only two consecutive VFP SP registers allowed here");
7613 }
7614
7615 end_of_line (str);
7616 return;
7617}
7618
7619static void
7620do_vfp_sp_from_reg (str)
7621 char *str;
7622{
7623 skip_whitespace (str);
7624
7625 if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7626 return;
7627
7628 if (skip_past_comma (&str) == FAIL
7629 || reg_required_here (&str, 12) == FAIL)
7630 {
7631 if (! inst.error)
7632 inst.error = BAD_ARGS;
7633 return;
7634 }
7635
7636 end_of_line (str);
7637 return;
7638}
7639
7640static void
7641do_vfp_reg_from_dp (str)
7642 char *str;
7643{
7644 skip_whitespace (str);
7645
7646 if (reg_required_here (&str, 12) == FAIL)
7647 return;
7648
7649 if (skip_past_comma (&str) == FAIL
7650 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
7651 {
7652 if (! inst.error)
7653 inst.error = BAD_ARGS;
7654 return;
7655 }
7656
7657 end_of_line (str);
7658 return;
7659}
7660
7661static void
7662do_vfp_reg2_from_dp (str)
7663 char *str;
7664{
7665 skip_whitespace (str);
7666
7667 if (reg_required_here (&str, 12) == FAIL)
7668 return;
7669
7670 if (skip_past_comma (&str) == FAIL
7671 || reg_required_here (&str, 16) == FAIL
7672 || skip_past_comma (&str) == FAIL
7673 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7674 {
7675 if (! inst.error)
7676 inst.error = BAD_ARGS;
7677 return;
7678 }
7679
7680 end_of_line (str);
7681 return;
7682}
7683
7684static void
7685do_vfp_dp_from_reg (str)
7686 char *str;
7687{
7688 skip_whitespace (str);
7689
7690 if (vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
7691 return;
7692
7693 if (skip_past_comma (&str) == FAIL
7694 || reg_required_here (&str, 12) == FAIL)
7695 {
7696 if (! inst.error)
7697 inst.error = BAD_ARGS;
7698 return;
7699 }
7700
7701 end_of_line (str);
7702 return;
7703}
7704
7705static void
7706do_vfp_dp_from_reg2 (str)
7707 char *str;
7708{
7709 skip_whitespace (str);
7710
7711 if (vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7712 return;
7713
7714 if (skip_past_comma (&str) == FAIL
7715 || reg_required_here (&str, 12) == FAIL
7716 || skip_past_comma (&str) == FAIL
7717 || reg_required_here (&str, 16))
7718 {
7719 if (! inst.error)
7720 inst.error = BAD_ARGS;
7721 return;
7722 }
7723
7724 end_of_line (str);
7725 return;
7726}
7727
7728static const struct vfp_reg *
7729vfp_psr_parse (str)
7730 char **str;
7731{
7732 char *start = *str;
7733 char c;
7734 char *p;
7735 const struct vfp_reg *vreg;
7736
7737 p = start;
7738
7739 /* Find the end of the current token. */
7740 do
7741 {
7742 c = *p++;
7743 }
7744 while (ISALPHA (c));
7745
7746 /* Mark it. */
7747 *--p = 0;
7748
cc8a6dd0 7749 for (vreg = vfp_regs + 0;
bfae80f2
RE
7750 vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg);
7751 vreg++)
7752 {
7753 if (strcmp (start, vreg->name) == 0)
7754 {
7755 *p = c;
7756 *str = p;
7757 return vreg;
7758 }
7759 }
7760
7761 *p = c;
7762 return NULL;
7763}
7764
7765static int
7766vfp_psr_required_here (str)
7767 char **str;
7768{
7769 char *start = *str;
7770 const struct vfp_reg *vreg;
7771
7772 vreg = vfp_psr_parse (str);
7773
7774 if (vreg)
7775 {
7776 inst.instruction |= vreg->regno;
7777 return SUCCESS;
7778 }
7779
7780 inst.error = _("VFP system register expected");
7781
7782 *str = start;
7783 return FAIL;
7784}
7785
7786static void
7787do_vfp_reg_from_ctrl (str)
7788 char *str;
7789{
7790 skip_whitespace (str);
7791
7792 if (reg_required_here (&str, 12) == FAIL)
7793 return;
7794
7795 if (skip_past_comma (&str) == FAIL
7796 || vfp_psr_required_here (&str) == FAIL)
7797 {
7798 if (! inst.error)
7799 inst.error = BAD_ARGS;
7800 return;
7801 }
7802
7803 end_of_line (str);
7804 return;
7805}
7806
7807static void
7808do_vfp_ctrl_from_reg (str)
7809 char *str;
7810{
7811 skip_whitespace (str);
7812
7813 if (vfp_psr_required_here (&str) == FAIL)
7814 return;
7815
7816 if (skip_past_comma (&str) == FAIL
7817 || reg_required_here (&str, 12) == FAIL)
7818 {
7819 if (! inst.error)
7820 inst.error = BAD_ARGS;
7821 return;
7822 }
7823
7824 end_of_line (str);
7825 return;
7826}
7827
7828static void
7829do_vfp_sp_ldst (str)
7830 char *str;
7831{
7832 skip_whitespace (str);
7833
7834 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7835 {
7836 if (!inst.error)
7837 inst.error = BAD_ARGS;
7838 return;
7839 }
7840
7841 if (skip_past_comma (&str) == FAIL
7842 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
7843 {
7844 if (!inst.error)
7845 inst.error = BAD_ARGS;
7846 return;
7847 }
7848
7849 end_of_line (str);
7850 return;
7851}
7852
7853static void
7854do_vfp_dp_ldst (str)
7855 char *str;
7856{
7857 skip_whitespace (str);
7858
7859 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7860 {
7861 if (!inst.error)
7862 inst.error = BAD_ARGS;
7863 return;
7864 }
7865
7866 if (skip_past_comma (&str) == FAIL
7867 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
7868 {
7869 if (!inst.error)
7870 inst.error = BAD_ARGS;
7871 return;
7872 }
7873
7874 end_of_line (str);
7875 return;
7876}
7877
7878/* Parse and encode a VFP SP register list, storing the initial
7879 register in position POS and returning the range as the result. If
7880 the string is invalid return FAIL (an invalid range). */
7881static long
7882vfp_sp_reg_list (str, pos)
7883 char **str;
7884 enum vfp_sp_reg_pos pos;
7885{
7886 long range = 0;
7887 int base_reg = 0;
7888 int new_base;
7889 long base_bits = 0;
7890 int count = 0;
7891 long tempinst;
7892 unsigned long mask = 0;
7893 int warned = 0;
7894
7895 if (**str != '{')
7896 return FAIL;
7897
7898 (*str)++;
7899 skip_whitespace (*str);
7900
7901 tempinst = inst.instruction;
7902
7903 do
7904 {
7905 inst.instruction = 0;
7906
7907 if ((new_base = vfp_sp_reg_required_here (str, pos)) == FAIL)
7908 return FAIL;
7909
7910 if (count == 0 || base_reg > new_base)
7911 {
7912 base_reg = new_base;
7913 base_bits = inst.instruction;
7914 }
7915
7916 if (mask & (1 << new_base))
7917 {
7918 inst.error = _("invalid register list");
7919 return FAIL;
7920 }
7921
7922 if ((mask >> new_base) != 0 && ! warned)
7923 {
7924 as_tsktsk (_("register list not in ascending order"));
7925 warned = 1;
7926 }
7927
7928 mask |= 1 << new_base;
7929 count++;
7930
7931 skip_whitespace (*str);
7932
7933 if (**str == '-') /* We have the start of a range expression */
7934 {
7935 int high_range;
7936
7937 (*str)++;
7938
7939 if ((high_range
7940 = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab))
7941 == FAIL)
7942 {
7943 inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
7944 return FAIL;
7945 }
7946
7947 if (high_range <= new_base)
7948 {
7949 inst.error = _("register range not in ascending order");
7950 return FAIL;
7951 }
7952
7953 for (new_base++; new_base <= high_range; new_base++)
7954 {
7955 if (mask & (1 << new_base))
7956 {
7957 inst.error = _("invalid register list");
7958 return FAIL;
7959 }
7960
7961 mask |= 1 << new_base;
7962 count++;
7963 }
7964 }
7965 }
7966 while (skip_past_comma (str) != FAIL);
7967
7968 if (**str != '}')
7969 {
7970 inst.error = _("invalid register list");
7971 return FAIL;
7972 }
7973
7974 (*str)++;
7975
7976 range = count;
7977
7978 /* Sanity check -- should have raised a parse error above. */
7979 if (count == 0 || count > 32)
c62e1cc3 7980 abort ();
bfae80f2
RE
7981
7982 /* Final test -- the registers must be consecutive. */
7983 while (count--)
7984 {
7985 if ((mask & (1 << base_reg++)) == 0)
7986 {
7987 inst.error = _("non-contiguous register range");
7988 return FAIL;
7989 }
7990 }
7991
7992 inst.instruction = tempinst | base_bits;
7993 return range;
7994}
7995
7996static long
7997vfp_dp_reg_list (str)
7998 char **str;
7999{
8000 long range = 0;
8001 int base_reg = 0;
8002 int new_base;
8003 int count = 0;
8004 long tempinst;
8005 unsigned long mask = 0;
8006 int warned = 0;
8007
8008 if (**str != '{')
8009 return FAIL;
8010
8011 (*str)++;
8012 skip_whitespace (*str);
8013
8014 tempinst = inst.instruction;
8015
8016 do
8017 {
8018 inst.instruction = 0;
8019
8020 if ((new_base = vfp_dp_reg_required_here (str, VFP_REG_Dd)) == FAIL)
8021 return FAIL;
8022
8023 if (count == 0 || base_reg > new_base)
8024 {
8025 base_reg = new_base;
8026 range = inst.instruction;
8027 }
8028
8029 if (mask & (1 << new_base))
8030 {
8031 inst.error = _("invalid register list");
8032 return FAIL;
8033 }
8034
8035 if ((mask >> new_base) != 0 && ! warned)
8036 {
8037 as_tsktsk (_("register list not in ascending order"));
8038 warned = 1;
8039 }
8040
8041 mask |= 1 << new_base;
8042 count++;
8043
8044 skip_whitespace (*str);
8045
8046 if (**str == '-') /* We have the start of a range expression */
8047 {
8048 int high_range;
8049
8050 (*str)++;
8051
8052 if ((high_range
8053 = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab))
8054 == FAIL)
8055 {
8056 inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
8057 return FAIL;
8058 }
8059
8060 if (high_range <= new_base)
8061 {
8062 inst.error = _("register range not in ascending order");
8063 return FAIL;
8064 }
8065
8066 for (new_base++; new_base <= high_range; new_base++)
8067 {
8068 if (mask & (1 << new_base))
8069 {
8070 inst.error = _("invalid register list");
8071 return FAIL;
8072 }
8073
8074 mask |= 1 << new_base;
8075 count++;
8076 }
8077 }
8078 }
8079 while (skip_past_comma (str) != FAIL);
8080
8081 if (**str != '}')
8082 {
8083 inst.error = _("invalid register list");
8084 return FAIL;
8085 }
8086
8087 (*str)++;
8088
8089 range |= 2 * count;
8090
8091 /* Sanity check -- should have raised a parse error above. */
8092 if (count == 0 || count > 16)
c62e1cc3 8093 abort ();
bfae80f2
RE
8094
8095 /* Final test -- the registers must be consecutive. */
8096 while (count--)
8097 {
8098 if ((mask & (1 << base_reg++)) == 0)
8099 {
8100 inst.error = _("non-contiguous register range");
8101 return FAIL;
8102 }
8103 }
8104
8105 inst.instruction = tempinst;
8106 return range;
8107}
8108
8109static void
c62e1cc3 8110vfp_sp_ldstm (str, ldstm_type)
bfae80f2
RE
8111 char *str;
8112 enum vfp_ldstm_type ldstm_type;
8113{
8114 long range;
8115
8116 skip_whitespace (str);
8117
8118 if (reg_required_here (&str, 16) == FAIL)
8119 return;
8120
8121 skip_whitespace (str);
8122
8123 if (*str == '!')
8124 {
8125 inst.instruction |= WRITE_BACK;
8126 str++;
8127 }
8128 else if (ldstm_type != VFP_LDSTMIA)
8129 {
8130 inst.error = _("this addressing mode requires base-register writeback");
8131 return;
8132 }
8133
8134 if (skip_past_comma (&str) == FAIL
8135 || (range = vfp_sp_reg_list (&str, VFP_REG_Sd)) == FAIL)
8136 {
8137 if (!inst.error)
8138 inst.error = BAD_ARGS;
8139 return;
8140 }
8141
8142 inst.instruction |= range;
8143 end_of_line (str);
8144}
8145
8146static void
c62e1cc3 8147vfp_dp_ldstm (str, ldstm_type)
bfae80f2
RE
8148 char *str;
8149 enum vfp_ldstm_type ldstm_type;
8150{
8151 long range;
8152
8153 skip_whitespace (str);
8154
8155 if (reg_required_here (&str, 16) == FAIL)
8156 return;
8157
8158 skip_whitespace (str);
8159
8160 if (*str == '!')
8161 {
8162 inst.instruction |= WRITE_BACK;
8163 str++;
8164 }
8165 else if (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX)
8166 {
8167 inst.error = _("this addressing mode requires base-register writeback");
8168 return;
8169 }
8170
8171 if (skip_past_comma (&str) == FAIL
8172 || (range = vfp_dp_reg_list (&str)) == FAIL)
8173 {
8174 if (!inst.error)
8175 inst.error = BAD_ARGS;
8176 return;
8177 }
8178
8179 if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
8180 range += 1;
8181
8182 inst.instruction |= range;
8183 end_of_line (str);
8184}
8185
8186static void
8187do_vfp_sp_ldstmia (str)
8188 char *str;
8189{
8190 vfp_sp_ldstm (str, VFP_LDSTMIA);
8191}
8192
8193static void
8194do_vfp_sp_ldstmdb (str)
8195 char *str;
8196{
8197 vfp_sp_ldstm (str, VFP_LDSTMDB);
8198}
8199
8200static void
8201do_vfp_dp_ldstmia (str)
8202 char *str;
8203{
8204 vfp_dp_ldstm (str, VFP_LDSTMIA);
8205}
8206
8207static void
8208do_vfp_dp_ldstmdb (str)
8209 char *str;
8210{
8211 vfp_dp_ldstm (str, VFP_LDSTMDB);
8212}
8213
8214static void
8215do_vfp_xp_ldstmia (str)
8216 char *str;
8217{
8218 vfp_dp_ldstm (str, VFP_LDSTMIAX);
8219}
8220
8221static void
8222do_vfp_xp_ldstmdb (str)
8223 char *str;
8224{
8225 vfp_dp_ldstm (str, VFP_LDSTMDBX);
8226}
8227
8228static void
8229do_vfp_sp_compare_z (str)
8230 char *str;
8231{
8232 skip_whitespace (str);
8233
8234 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8235 {
8236 if (!inst.error)
8237 inst.error = BAD_ARGS;
8238 return;
8239 }
8240
8241 end_of_line (str);
8242 return;
8243}
8244
8245static void
8246do_vfp_dp_compare_z (str)
8247 char *str;
8248{
8249 skip_whitespace (str);
8250
8251 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8252 {
8253 if (!inst.error)
8254 inst.error = BAD_ARGS;
8255 return;
8256 }
8257
8258 end_of_line (str);
8259 return;
8260}
8261
8262static void
8263do_vfp_dp_sp_cvt (str)
8264 char *str;
8265{
8266 skip_whitespace (str);
8267
8268 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8269 return;
8270
8271 if (skip_past_comma (&str) == FAIL
8272 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
8273 {
8274 if (! inst.error)
8275 inst.error = BAD_ARGS;
8276 return;
8277 }
8278
8279 end_of_line (str);
8280 return;
8281}
8282
8283static void
8284do_vfp_sp_dp_cvt (str)
8285 char *str;
8286{
8287 skip_whitespace (str);
8288
8289 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8290 return;
8291
8292 if (skip_past_comma (&str) == FAIL
8293 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8294 {
8295 if (! inst.error)
8296 inst.error = BAD_ARGS;
8297 return;
8298 }
8299
8300 end_of_line (str);
8301 return;
8302}
8303
8304/* Thumb specific routines. */
8305
8306/* Parse and validate that a register is of the right form, this saves
8307 repeated checking of this information in many similar cases.
8308 Unlike the 32-bit case we do not insert the register into the opcode
8309 here, since the position is often unknown until the full instruction
8310 has been parsed. */
8311
8312static int
8313thumb_reg (strp, hi_lo)
8314 char ** strp;
8315 int hi_lo;
8316{
8317 int reg;
8318
8319 if ((reg = reg_required_here (strp, -1)) == FAIL)
8320 return FAIL;
8321
8322 switch (hi_lo)
8323 {
8324 case THUMB_REG_LO:
8325 if (reg > 7)
8326 {
8327 inst.error = _("lo register required");
8328 return FAIL;
8329 }
8330 break;
8331
8332 case THUMB_REG_HI:
8333 if (reg < 8)
8334 {
8335 inst.error = _("hi register required");
8336 return FAIL;
8337 }
8338 break;
8339
8340 default:
8341 break;
8342 }
8343
8344 return reg;
8345}
8346
8347/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
8348 was SUB. */
8349
8350static void
8351thumb_add_sub (str, subtract)
8352 char * str;
8353 int subtract;
8354{
8355 int Rd, Rs, Rn = FAIL;
8356
8357 skip_whitespace (str);
8358
8359 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
8360 || skip_past_comma (&str) == FAIL)
8361 {
8362 if (! inst.error)
8363 inst.error = BAD_ARGS;
8364 return;
8365 }
8366
8367 if (is_immediate_prefix (*str))
8368 {
8369 Rs = Rd;
8370 str++;
8371 if (my_get_expression (&inst.reloc.exp, &str))
8372 return;
8373 }
8374 else
8375 {
8376 if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8377 return;
8378
8379 if (skip_past_comma (&str) == FAIL)
8380 {
8381 /* Two operand format, shuffle the registers
8382 and pretend there are 3. */
8383 Rn = Rs;
8384 Rs = Rd;
8385 }
8386 else if (is_immediate_prefix (*str))
8387 {
8388 str++;
8389 if (my_get_expression (&inst.reloc.exp, &str))
8390 return;
8391 }
8392 else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8393 return;
8394 }
8395
8396 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8397 for the latter case, EXPR contains the immediate that was found. */
8398 if (Rn != FAIL)
8399 {
8400 /* All register format. */
8401 if (Rd > 7 || Rs > 7 || Rn > 7)
8402 {
8403 if (Rs != Rd)
8404 {
8405 inst.error = _("dest and source1 must be the same register");
8406 return;
8407 }
8408
8409 /* Can't do this for SUB. */
8410 if (subtract)
8411 {
8412 inst.error = _("subtract valid only on lo regs");
8413 return;
8414 }
8415
8416 inst.instruction = (T_OPCODE_ADD_HI
8417 | (Rd > 7 ? THUMB_H1 : 0)
8418 | (Rn > 7 ? THUMB_H2 : 0));
8419 inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
8420 }
8421 else
8422 {
8423 inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
8424 inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8425 }
8426 }
8427 else
8428 {
8429 /* Immediate expression, now things start to get nasty. */
8430
8431 /* First deal with HI regs, only very restricted cases allowed:
8432 Adjusting SP, and using PC or SP to get an address. */
8433 if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8434 || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
8435 {
8436 inst.error = _("invalid Hi register with immediate");
8437 return;
8438 }
8439
8440 if (inst.reloc.exp.X_op != O_constant)
8441 {
8442 /* Value isn't known yet, all we can do is store all the fragments
8443 we know about in the instruction and let the reloc hacking
8444 work it all out. */
8445 inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
8446 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8447 }
8448 else
8449 {
8450 int offset = inst.reloc.exp.X_add_number;
8451
8452 if (subtract)
358b94bd 8453 offset = - offset;
bfae80f2
RE
8454
8455 if (offset < 0)
8456 {
358b94bd 8457 offset = - offset;
bfae80f2
RE
8458 subtract = 1;
8459
8460 /* Quick check, in case offset is MIN_INT. */
8461 if (offset < 0)
8462 {
8463 inst.error = _("immediate value out of range");
8464 return;
8465 }
8466 }
358b94bd
NC
8467 /* Note - you cannot convert a subtract of 0 into an
8468 add of 0 because the carry flag is set differently. */
8469 else if (offset > 0)
bfae80f2
RE
8470 subtract = 0;
8471
8472 if (Rd == REG_SP)
8473 {
8474 if (offset & ~0x1fc)
8475 {
8476 inst.error = _("invalid immediate value for stack adjust");
8477 return;
b99bd4ef
NC
8478 }
8479 inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
8480 inst.instruction |= offset >> 2;
8481 }
8482 else if (Rs == REG_PC || Rs == REG_SP)
8483 {
8484 if (subtract
8485 || (offset & ~0x3fc))
8486 {
8487 inst.error = _("invalid immediate for address calculation");
8488 return;
8489 }
8490 inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
8491 : T_OPCODE_ADD_SP);
8492 inst.instruction |= (Rd << 8) | (offset >> 2);
8493 }
8494 else if (Rs == Rd)
8495 {
8496 if (offset & ~0xff)
8497 {
8498 inst.error = _("immediate value out of range");
8499 return;
8500 }
8501 inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
8502 inst.instruction |= (Rd << 8) | offset;
8503 }
8504 else
8505 {
8506 if (offset & ~0x7)
8507 {
8508 inst.error = _("immediate value out of range");
8509 return;
8510 }
8511 inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
8512 inst.instruction |= Rd | (Rs << 3) | (offset << 6);
8513 }
8514 }
8515 }
8516
8517 end_of_line (str);
8518}
8519
8520static void
8521thumb_shift (str, shift)
8522 char * str;
8523 int shift;
8524{
8525 int Rd, Rs, Rn = FAIL;
8526
8527 skip_whitespace (str);
8528
8529 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8530 || skip_past_comma (&str) == FAIL)
8531 {
8532 if (! inst.error)
8533 inst.error = BAD_ARGS;
8534 return;
8535 }
8536
8537 if (is_immediate_prefix (*str))
8538 {
8539 /* Two operand immediate format, set Rs to Rd. */
8540 Rs = Rd;
8541 str ++;
8542 if (my_get_expression (&inst.reloc.exp, &str))
8543 return;
8544 }
8545 else
8546 {
8547 if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8548 return;
8549
8550 if (skip_past_comma (&str) == FAIL)
8551 {
8552 /* Two operand format, shuffle the registers
8553 and pretend there are 3. */
8554 Rn = Rs;
8555 Rs = Rd;
8556 }
8557 else if (is_immediate_prefix (*str))
8558 {
8559 str++;
8560 if (my_get_expression (&inst.reloc.exp, &str))
8561 return;
8562 }
8563 else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8564 return;
8565 }
8566
8567 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8568 for the latter case, EXPR contains the immediate that was found. */
8569
8570 if (Rn != FAIL)
8571 {
8572 if (Rs != Rd)
8573 {
8574 inst.error = _("source1 and dest must be same register");
8575 return;
8576 }
8577
8578 switch (shift)
8579 {
8580 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
8581 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
8582 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
8583 }
8584
8585 inst.instruction |= Rd | (Rn << 3);
8586 }
8587 else
8588 {
8589 switch (shift)
8590 {
8591 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
8592 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
8593 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
8594 }
8595
8596 if (inst.reloc.exp.X_op != O_constant)
8597 {
8598 /* Value isn't known yet, create a dummy reloc and let reloc
8599 hacking fix it up. */
8600 inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
8601 }
8602 else
8603 {
8604 unsigned shift_value = inst.reloc.exp.X_add_number;
8605
8606 if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
8607 {
f03698e6 8608 inst.error = _("invalid immediate for shift");
b99bd4ef
NC
8609 return;
8610 }
8611
8612 /* Shifts of zero are handled by converting to LSL. */
8613 if (shift_value == 0)
8614 inst.instruction = T_OPCODE_LSL_I;
8615
8616 /* Shifts of 32 are encoded as a shift of zero. */
8617 if (shift_value == 32)
8618 shift_value = 0;
8619
8620 inst.instruction |= shift_value << 6;
8621 }
8622
8623 inst.instruction |= Rd | (Rs << 3);
8624 }
8625
8626 end_of_line (str);
8627}
8628
8629static void
8630thumb_mov_compare (str, move)
8631 char * str;
8632 int move;
8633{
8634 int Rd, Rs = FAIL;
8635
8636 skip_whitespace (str);
8637
8638 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
8639 || skip_past_comma (&str) == FAIL)
8640 {
8641 if (! inst.error)
8642 inst.error = BAD_ARGS;
8643 return;
8644 }
8645
8646 if (is_immediate_prefix (*str))
8647 {
8648 str++;
8649 if (my_get_expression (&inst.reloc.exp, &str))
8650 return;
8651 }
8652 else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8653 return;
8654
8655 if (Rs != FAIL)
8656 {
8657 if (Rs < 8 && Rd < 8)
8658 {
8659 if (move == THUMB_MOVE)
8660 /* A move of two lowregs is encoded as ADD Rd, Rs, #0
8661 since a MOV instruction produces unpredictable results. */
8662 inst.instruction = T_OPCODE_ADD_I3;
8663 else
8664 inst.instruction = T_OPCODE_CMP_LR;
8665 inst.instruction |= Rd | (Rs << 3);
8666 }
8667 else
8668 {
8669 if (move == THUMB_MOVE)
8670 inst.instruction = T_OPCODE_MOV_HR;
8671 else
8672 inst.instruction = T_OPCODE_CMP_HR;
8673
8674 if (Rd > 7)
8675 inst.instruction |= THUMB_H1;
8676
8677 if (Rs > 7)
8678 inst.instruction |= THUMB_H2;
8679
8680 inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
8681 }
8682 }
8683 else
8684 {
8685 if (Rd > 7)
8686 {
8687 inst.error = _("only lo regs allowed with immediate");
8688 return;
8689 }
8690
8691 if (move == THUMB_MOVE)
8692 inst.instruction = T_OPCODE_MOV_I8;
8693 else
8694 inst.instruction = T_OPCODE_CMP_I8;
8695
8696 inst.instruction |= Rd << 8;
8697
8698 if (inst.reloc.exp.X_op != O_constant)
8699 inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
8700 else
8701 {
8702 unsigned value = inst.reloc.exp.X_add_number;
8703
8704 if (value > 255)
8705 {
8706 inst.error = _("invalid immediate");
8707 return;
8708 }
8709
8710 inst.instruction |= value;
8711 }
8712 }
8713
8714 end_of_line (str);
8715}
8716
8717static void
8718thumb_load_store (str, load_store, size)
8719 char * str;
8720 int load_store;
8721 int size;
8722{
8723 int Rd, Rb, Ro = FAIL;
8724
8725 skip_whitespace (str);
8726
8727 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8728 || skip_past_comma (&str) == FAIL)
8729 {
8730 if (! inst.error)
8731 inst.error = BAD_ARGS;
8732 return;
8733 }
8734
8735 if (*str == '[')
8736 {
8737 str++;
8738 if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8739 return;
8740
8741 if (skip_past_comma (&str) != FAIL)
8742 {
8743 if (is_immediate_prefix (*str))
8744 {
8745 str++;
8746 if (my_get_expression (&inst.reloc.exp, &str))
8747 return;
8748 }
8749 else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8750 return;
8751 }
8752 else
8753 {
8754 inst.reloc.exp.X_op = O_constant;
8755 inst.reloc.exp.X_add_number = 0;
8756 }
8757
8758 if (*str != ']')
8759 {
8760 inst.error = _("expected ']'");
8761 return;
8762 }
8763 str++;
8764 }
8765 else if (*str == '=')
8766 {
f03698e6
RE
8767 if (load_store != THUMB_LOAD)
8768 {
8769 inst.error = _("invalid pseudo operation");
8770 return;
8771 }
8772
b99bd4ef
NC
8773 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
8774 str++;
8775
8776 skip_whitespace (str);
8777
8778 if (my_get_expression (& inst.reloc.exp, & str))
8779 return;
8780
8781 end_of_line (str);
8782
8783 if ( inst.reloc.exp.X_op != O_constant
8784 && inst.reloc.exp.X_op != O_symbol)
8785 {
8786 inst.error = "Constant expression expected";
8787 return;
8788 }
8789
8790 if (inst.reloc.exp.X_op == O_constant
8791 && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
8792 {
8793 /* This can be done with a mov instruction. */
8794
8795 inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8);
8796 inst.instruction |= inst.reloc.exp.X_add_number;
8797 return;
8798 }
8799
8800 /* Insert into literal pool. */
8801 if (add_to_lit_pool () == FAIL)
8802 {
8803 if (!inst.error)
8804 inst.error = "literal pool insertion failed";
8805 return;
8806 }
8807
8808 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8809 inst.reloc.pc_rel = 1;
8810 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8811 /* Adjust ARM pipeline offset to Thumb. */
8812 inst.reloc.exp.X_add_number += 4;
8813
8814 return;
8815 }
8816 else
8817 {
8818 if (my_get_expression (&inst.reloc.exp, &str))
8819 return;
8820
8821 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8822 inst.reloc.pc_rel = 1;
8823 inst.reloc.exp.X_add_number -= 4; /* Pipeline offset. */
8824 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8825 end_of_line (str);
8826 return;
8827 }
8828
8829 if (Rb == REG_PC || Rb == REG_SP)
8830 {
8831 if (size != THUMB_WORD)
8832 {
8833 inst.error = _("byte or halfword not valid for base register");
8834 return;
8835 }
8836 else if (Rb == REG_PC && load_store != THUMB_LOAD)
8837 {
f03698e6 8838 inst.error = _("r15 based store not allowed");
b99bd4ef
NC
8839 return;
8840 }
8841 else if (Ro != FAIL)
8842 {
f03698e6 8843 inst.error = _("invalid base register for register offset");
b99bd4ef
NC
8844 return;
8845 }
8846
8847 if (Rb == REG_PC)
8848 inst.instruction = T_OPCODE_LDR_PC;
8849 else if (load_store == THUMB_LOAD)
8850 inst.instruction = T_OPCODE_LDR_SP;
8851 else
8852 inst.instruction = T_OPCODE_STR_SP;
8853
8854 inst.instruction |= Rd << 8;
8855 if (inst.reloc.exp.X_op == O_constant)
8856 {
8857 unsigned offset = inst.reloc.exp.X_add_number;
8858
8859 if (offset & ~0x3fc)
8860 {
8861 inst.error = _("invalid offset");
8862 return;
8863 }
8864
8865 inst.instruction |= offset >> 2;
8866 }
8867 else
8868 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8869 }
8870 else if (Rb > 7)
8871 {
8872 inst.error = _("invalid base register in load/store");
8873 return;
8874 }
8875 else if (Ro == FAIL)
8876 {
8877 /* Immediate offset. */
8878 if (size == THUMB_WORD)
8879 inst.instruction = (load_store == THUMB_LOAD
8880 ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
8881 else if (size == THUMB_HALFWORD)
8882 inst.instruction = (load_store == THUMB_LOAD
8883 ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
8884 else
8885 inst.instruction = (load_store == THUMB_LOAD
8886 ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
8887
8888 inst.instruction |= Rd | (Rb << 3);
8889
8890 if (inst.reloc.exp.X_op == O_constant)
8891 {
8892 unsigned offset = inst.reloc.exp.X_add_number;
8893
8894 if (offset & ~(0x1f << size))
8895 {
f03698e6 8896 inst.error = _("invalid offset");
b99bd4ef
NC
8897 return;
8898 }
8899 inst.instruction |= (offset >> size) << 6;
8900 }
8901 else
8902 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8903 }
8904 else
8905 {
8906 /* Register offset. */
8907 if (size == THUMB_WORD)
8908 inst.instruction = (load_store == THUMB_LOAD
8909 ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
8910 else if (size == THUMB_HALFWORD)
8911 inst.instruction = (load_store == THUMB_LOAD
8912 ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
8913 else
8914 inst.instruction = (load_store == THUMB_LOAD
8915 ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
8916
8917 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
8918 }
8919
8920 end_of_line (str);
8921}
8922
404ff6b5
AH
8923/* A register must be given at this point.
8924
404ff6b5
AH
8925 Shift is the place to put it in inst.instruction.
8926
404ff6b5
AH
8927 Restores input start point on err.
8928 Returns the reg#, or FAIL. */
8929
8930static int
63e63b07 8931mav_reg_required_here (str, shift, regtype)
404ff6b5
AH
8932 char ** str;
8933 int shift;
6c43fab6 8934 enum arm_reg_type regtype;
404ff6b5 8935{
6c43fab6
RE
8936 int reg;
8937 char *start = *str;
404ff6b5 8938
6c43fab6 8939 if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL)
404ff6b5 8940 {
404ff6b5
AH
8941 if (shift >= 0)
8942 inst.instruction |= reg << shift;
8943
6c43fab6 8944 return reg;
404ff6b5
AH
8945 }
8946
6c43fab6 8947 /* Restore the start point. */
404ff6b5 8948 *str = start;
cc8a6dd0 8949
404ff6b5
AH
8950 /* In the few cases where we might be able to accept something else
8951 this error can be overridden. */
6c43fab6 8952 inst.error = _(all_reg_maps[regtype].expected);
cc8a6dd0 8953
404ff6b5
AH
8954 return FAIL;
8955}
8956
63e63b07 8957/* Cirrus Maverick Instructions. */
404ff6b5
AH
8958
8959/* Wrapper functions. */
8960
8961static void
63e63b07 8962do_mav_binops_1a (str)
6c43fab6
RE
8963 char * str;
8964{
63e63b07 8965 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF);
6c43fab6
RE
8966}
8967
8968static void
63e63b07 8969do_mav_binops_1b (str)
6c43fab6
RE
8970 char * str;
8971{
63e63b07 8972 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD);
6c43fab6
RE
8973}
8974
8975static void
63e63b07 8976do_mav_binops_1c (str)
404ff6b5 8977 char * str;
404ff6b5 8978{
63e63b07 8979 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX);
404ff6b5
AH
8980}
8981
8982static void
63e63b07 8983do_mav_binops_1d (str)
404ff6b5 8984 char * str;
404ff6b5 8985{
63e63b07 8986 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF);
404ff6b5
AH
8987}
8988
8989static void
63e63b07 8990do_mav_binops_1e (str)
404ff6b5 8991 char * str;
404ff6b5 8992{
63e63b07 8993 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD);
404ff6b5
AH
8994}
8995
8996static void
63e63b07 8997do_mav_binops_1f (str)
404ff6b5 8998 char * str;
404ff6b5 8999{
63e63b07 9000 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF);
404ff6b5
AH
9001}
9002
9003static void
63e63b07 9004do_mav_binops_1g (str)
404ff6b5 9005 char * str;
404ff6b5 9006{
63e63b07 9007 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD);
404ff6b5
AH
9008}
9009
9010static void
63e63b07 9011do_mav_binops_1h (str)
404ff6b5 9012 char * str;
404ff6b5 9013{
63e63b07 9014 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX);
404ff6b5
AH
9015}
9016
6c43fab6 9017static void
63e63b07 9018do_mav_binops_1i (str)
6c43fab6
RE
9019 char * str;
9020{
63e63b07 9021 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX);
6c43fab6
RE
9022}
9023
9024static void
63e63b07 9025do_mav_binops_1j (str)
6c43fab6
RE
9026 char * str;
9027{
63e63b07 9028 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX);
6c43fab6
RE
9029}
9030
9031static void
63e63b07 9032do_mav_binops_1k (str)
6c43fab6
RE
9033 char * str;
9034{
63e63b07 9035 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX);
6c43fab6
RE
9036}
9037
9038static void
63e63b07 9039do_mav_binops_1l (str)
6c43fab6
RE
9040 char * str;
9041{
63e63b07 9042 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF);
6c43fab6
RE
9043}
9044
9045static void
63e63b07 9046do_mav_binops_1m (str)
6c43fab6
RE
9047 char * str;
9048{
63e63b07 9049 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD);
6c43fab6
RE
9050}
9051
9052static void
63e63b07 9053do_mav_binops_1n (str)
6c43fab6
RE
9054 char * str;
9055{
63e63b07 9056 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9057}
9058
9059static void
63e63b07 9060do_mav_binops_1o (str)
6c43fab6
RE
9061 char * str;
9062{
63e63b07 9063 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9064}
9065
9066static void
63e63b07 9067do_mav_binops_2a (str)
6c43fab6
RE
9068 char * str;
9069{
63e63b07 9070 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN);
6c43fab6
RE
9071}
9072
9073static void
63e63b07 9074do_mav_binops_2b (str)
6c43fab6
RE
9075 char * str;
9076{
63e63b07 9077 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN);
6c43fab6
RE
9078}
9079
9080static void
63e63b07 9081do_mav_binops_2c (str)
6c43fab6
RE
9082 char * str;
9083{
63e63b07 9084 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN);
6c43fab6
RE
9085}
9086
9087static void
63e63b07 9088do_mav_binops_3a (str)
6c43fab6
RE
9089 char * str;
9090{
63e63b07 9091 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX);
6c43fab6
RE
9092}
9093
9094static void
63e63b07 9095do_mav_binops_3b (str)
6c43fab6
RE
9096 char * str;
9097{
63e63b07 9098 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX);
6c43fab6
RE
9099}
9100
9101static void
63e63b07 9102do_mav_binops_3c (str)
6c43fab6
RE
9103 char * str;
9104{
63e63b07 9105 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX);
6c43fab6
RE
9106}
9107
9108static void
63e63b07 9109do_mav_binops_3d (str)
6c43fab6
RE
9110 char * str;
9111{
63e63b07 9112 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX);
6c43fab6
RE
9113}
9114
9115static void
63e63b07 9116do_mav_triple_4a (str)
6c43fab6
RE
9117 char * str;
9118{
63e63b07 9119 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN);
6c43fab6
RE
9120}
9121
9122static void
63e63b07 9123do_mav_triple_4b (str)
6c43fab6
RE
9124 char * str;
9125{
63e63b07 9126 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN);
6c43fab6
RE
9127}
9128
9129static void
63e63b07 9130do_mav_triple_5a (str)
6c43fab6
RE
9131 char * str;
9132{
63e63b07 9133 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF);
6c43fab6
RE
9134}
9135
9136static void
63e63b07 9137do_mav_triple_5b (str)
6c43fab6
RE
9138 char * str;
9139{
63e63b07 9140 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD);
6c43fab6
RE
9141}
9142
9143static void
63e63b07 9144do_mav_triple_5c (str)
6c43fab6
RE
9145 char * str;
9146{
63e63b07 9147 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9148}
9149
9150static void
63e63b07 9151do_mav_triple_5d (str)
6c43fab6
RE
9152 char * str;
9153{
63e63b07 9154 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9155}
9156
9157static void
63e63b07 9158do_mav_triple_5e (str)
6c43fab6
RE
9159 char * str;
9160{
63e63b07 9161 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF);
6c43fab6
RE
9162}
9163
9164static void
63e63b07 9165do_mav_triple_5f (str)
6c43fab6
RE
9166 char * str;
9167{
63e63b07 9168 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD);
6c43fab6
RE
9169}
9170
9171static void
63e63b07 9172do_mav_triple_5g (str)
6c43fab6
RE
9173 char * str;
9174{
63e63b07 9175 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9176}
9177
9178static void
63e63b07 9179do_mav_triple_5h (str)
6c43fab6
RE
9180 char * str;
9181{
63e63b07 9182 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9183}
9184
9185static void
63e63b07 9186do_mav_quad_6a (str)
6c43fab6
RE
9187 char * str;
9188{
63e63b07 9189 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX,
6c43fab6
RE
9190 REG_TYPE_MVFX);
9191}
9192
9193static void
63e63b07 9194do_mav_quad_6b (str)
6c43fab6
RE
9195 char * str;
9196{
63e63b07 9197 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX,
6c43fab6
RE
9198 REG_TYPE_MVFX);
9199}
9200
cc8a6dd0 9201/* cfmvsc32<cond> DSPSC,MVFX[15:0]. */
404ff6b5 9202static void
63e63b07 9203do_mav_dspsc_1 (str)
404ff6b5 9204 char * str;
404ff6b5 9205{
6c43fab6
RE
9206 skip_whitespace (str);
9207
9208 /* cfmvsc32. */
63e63b07 9209 if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL
6c43fab6 9210 || skip_past_comma (&str) == FAIL
63e63b07 9211 || mav_reg_required_here (&str, 16, REG_TYPE_MVFX) == FAIL)
6c43fab6
RE
9212 {
9213 if (!inst.error)
9214 inst.error = BAD_ARGS;
9215
9216 return;
9217 }
9218
9219 end_of_line (str);
404ff6b5
AH
9220}
9221
6c43fab6 9222/* cfmv32sc<cond> MVFX[15:0],DSPSC. */
404ff6b5 9223static void
63e63b07 9224do_mav_dspsc_2 (str)
404ff6b5 9225 char * str;
404ff6b5 9226{
6c43fab6
RE
9227 skip_whitespace (str);
9228
9229 /* cfmv32sc. */
63e63b07 9230 if (mav_reg_required_here (&str, 0, REG_TYPE_MVFX) == FAIL
6c43fab6 9231 || skip_past_comma (&str) == FAIL
63e63b07 9232 || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL)
6c43fab6
RE
9233 {
9234 if (!inst.error)
9235 inst.error = BAD_ARGS;
9236
9237 return;
9238 }
9239
9240 end_of_line (str);
404ff6b5
AH
9241}
9242
9243static void
63e63b07 9244do_mav_shift_1 (str)
404ff6b5 9245 char * str;
404ff6b5 9246{
63e63b07 9247 do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX);
404ff6b5
AH
9248}
9249
9250static void
63e63b07 9251do_mav_shift_2 (str)
404ff6b5 9252 char * str;
404ff6b5 9253{
63e63b07 9254 do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX);
404ff6b5
AH
9255}
9256
9257static void
63e63b07 9258do_mav_ldst_1 (str)
404ff6b5 9259 char * str;
404ff6b5 9260{
63e63b07 9261 do_mav_ldst (str, REG_TYPE_MVF);
404ff6b5
AH
9262}
9263
9264static void
63e63b07 9265do_mav_ldst_2 (str)
404ff6b5 9266 char * str;
404ff6b5 9267{
63e63b07 9268 do_mav_ldst (str, REG_TYPE_MVD);
404ff6b5
AH
9269}
9270
9271static void
63e63b07 9272do_mav_ldst_3 (str)
404ff6b5 9273 char * str;
404ff6b5 9274{
63e63b07 9275 do_mav_ldst (str, REG_TYPE_MVFX);
404ff6b5
AH
9276}
9277
9278static void
63e63b07 9279do_mav_ldst_4 (str)
404ff6b5 9280 char * str;
404ff6b5 9281{
63e63b07 9282 do_mav_ldst (str, REG_TYPE_MVDX);
404ff6b5
AH
9283}
9284
9285/* Isnsn like "foo X,Y". */
9286
9287static void
63e63b07 9288do_mav_binops (str, mode, reg0, reg1)
404ff6b5 9289 char * str;
404ff6b5 9290 int mode;
6c43fab6
RE
9291 enum arm_reg_type reg0;
9292 enum arm_reg_type reg1;
404ff6b5 9293{
6c43fab6 9294 int shift0, shift1;
404ff6b5 9295
6c43fab6
RE
9296 shift0 = mode & 0xff;
9297 shift1 = (mode >> 8) & 0xff;
404ff6b5
AH
9298
9299 skip_whitespace (str);
9300
63e63b07 9301 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
404ff6b5 9302 || skip_past_comma (&str) == FAIL
63e63b07 9303 || mav_reg_required_here (&str, shift1, reg1) == FAIL)
404ff6b5
AH
9304 {
9305 if (!inst.error)
9306 inst.error = BAD_ARGS;
9307 }
9308 else
9309 end_of_line (str);
404ff6b5
AH
9310}
9311
9312/* Isnsn like "foo X,Y,Z". */
9313
9314static void
63e63b07 9315do_mav_triple (str, mode, reg0, reg1, reg2)
404ff6b5 9316 char * str;
404ff6b5 9317 int mode;
6c43fab6
RE
9318 enum arm_reg_type reg0;
9319 enum arm_reg_type reg1;
9320 enum arm_reg_type reg2;
404ff6b5 9321{
6c43fab6 9322 int shift0, shift1, shift2;
404ff6b5 9323
6c43fab6
RE
9324 shift0 = mode & 0xff;
9325 shift1 = (mode >> 8) & 0xff;
9326 shift2 = (mode >> 16) & 0xff;
404ff6b5
AH
9327
9328 skip_whitespace (str);
9329
63e63b07 9330 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
404ff6b5 9331 || skip_past_comma (&str) == FAIL
63e63b07 9332 || mav_reg_required_here (&str, shift1, reg1) == FAIL
404ff6b5 9333 || skip_past_comma (&str) == FAIL
63e63b07 9334 || mav_reg_required_here (&str, shift2, reg2) == FAIL)
404ff6b5
AH
9335 {
9336 if (!inst.error)
9337 inst.error = BAD_ARGS;
9338 }
9339 else
9340 end_of_line (str);
404ff6b5
AH
9341}
9342
9343/* Isnsn like "foo W,X,Y,Z".
9344 where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */
9345
9346static void
63e63b07 9347do_mav_quad (str, mode, reg0, reg1, reg2, reg3)
404ff6b5 9348 char * str;
404ff6b5 9349 int mode;
6c43fab6
RE
9350 enum arm_reg_type reg0;
9351 enum arm_reg_type reg1;
9352 enum arm_reg_type reg2;
9353 enum arm_reg_type reg3;
404ff6b5 9354{
6c43fab6 9355 int shift0, shift1, shift2, shift3;
404ff6b5 9356
6c43fab6
RE
9357 shift0= mode & 0xff;
9358 shift1 = (mode >> 8) & 0xff;
9359 shift2 = (mode >> 16) & 0xff;
9360 shift3 = (mode >> 24) & 0xff;
404ff6b5
AH
9361
9362 skip_whitespace (str);
9363
63e63b07 9364 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
404ff6b5 9365 || skip_past_comma (&str) == FAIL
63e63b07 9366 || mav_reg_required_here (&str, shift1, reg1) == FAIL
404ff6b5 9367 || skip_past_comma (&str) == FAIL
63e63b07 9368 || mav_reg_required_here (&str, shift2, reg2) == FAIL
404ff6b5 9369 || skip_past_comma (&str) == FAIL
63e63b07 9370 || mav_reg_required_here (&str, shift3, reg3) == FAIL)
404ff6b5
AH
9371 {
9372 if (!inst.error)
9373 inst.error = BAD_ARGS;
9374 }
9375 else
9376 end_of_line (str);
404ff6b5
AH
9377}
9378
63e63b07 9379/* Maverick shift immediate instructions.
404ff6b5
AH
9380 cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
9381 cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */
9382
9383static void
63e63b07 9384do_mav_shift (str, reg0, reg1)
404ff6b5 9385 char * str;
6c43fab6
RE
9386 enum arm_reg_type reg0;
9387 enum arm_reg_type reg1;
404ff6b5
AH
9388{
9389 int error;
9390 int imm, neg = 0;
9391
9392 skip_whitespace (str);
9393
9394 error = 0;
9395
63e63b07 9396 if (mav_reg_required_here (&str, 12, reg0) == FAIL
404ff6b5 9397 || skip_past_comma (&str) == FAIL
63e63b07 9398 || mav_reg_required_here (&str, 16, reg1) == FAIL
404ff6b5
AH
9399 || skip_past_comma (&str) == FAIL)
9400 {
9401 if (!inst.error)
9402 inst.error = BAD_ARGS;
9403 return;
9404 }
9405
9406 /* Calculate the immediate operand.
9407 The operand is a 7bit signed number. */
9408 skip_whitespace (str);
9409
9410 if (*str == '#')
9411 ++str;
9412
8420dfca 9413 if (!ISDIGIT (*str) && *str != '-')
404ff6b5
AH
9414 {
9415 inst.error = _("expecting immediate, 7bit operand");
9416 return;
9417 }
9418
9419 if (*str == '-')
9420 {
9421 neg = 1;
9422 ++str;
9423 }
9424
8420dfca 9425 for (imm = 0; *str && ISDIGIT (*str); ++str)
404ff6b5
AH
9426 imm = imm * 10 + *str - '0';
9427
9428 if (imm > 64)
9429 {
9430 inst.error = _("immediate out of range");
9431 return;
9432 }
9433
9434 /* Make negative imm's into 7bit signed numbers. */
9435 if (neg)
9436 {
9437 imm = -imm;
9438 imm &= 0x0000007f;
9439 }
9440
9441 /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
9442 Bits 5-7 of the insn should have bits 4-6 of the immediate.
9443 Bit 4 should be 0. */
9444 imm = (imm & 0xf) | ((imm & 0x70) << 1);
9445
9446 inst.instruction |= imm;
404ff6b5 9447 end_of_line (str);
404ff6b5
AH
9448}
9449
9450static int
63e63b07 9451mav_parse_offset (str, negative)
404ff6b5
AH
9452 char ** str;
9453 int *negative;
9454{
9455 char * p = *str;
9456 int offset;
9457
9458 *negative = 0;
9459
9460 skip_whitespace (p);
9461
9462 if (*p == '#')
9463 ++p;
9464
9465 if (*p == '-')
9466 {
9467 *negative = 1;
9468 ++p;
9469 }
9470
8420dfca 9471 if (!ISDIGIT (*p))
404ff6b5
AH
9472 {
9473 inst.error = _("offset expected");
9474 return 0;
9475 }
9476
8420dfca 9477 for (offset = 0; *p && ISDIGIT (*p); ++p)
404ff6b5
AH
9478 offset = offset * 10 + *p - '0';
9479
9480 if (offset > 0xff)
9481 {
9482 inst.error = _("offset out of range");
9483 return 0;
9484 }
9485
9486 *str = p;
9487
9488 return *negative ? -offset : offset;
9489}
9490
63e63b07 9491/* Maverick load/store instructions.
404ff6b5
AH
9492 <insn><cond> CRd,[Rn,<offset>]{!}.
9493 <insn><cond> CRd,[Rn],<offset>. */
9494
9495static void
63e63b07 9496do_mav_ldst (str, reg0)
404ff6b5 9497 char * str;
6c43fab6 9498 enum arm_reg_type reg0;
404ff6b5
AH
9499{
9500 int offset, negative;
404ff6b5
AH
9501
9502 skip_whitespace (str);
9503
63e63b07 9504 if (mav_reg_required_here (&str, 12, reg0) == FAIL
6c43fab6 9505 || skip_past_comma (&str) == FAIL
404ff6b5 9506 || *str++ != '['
6c43fab6 9507 || reg_required_here (&str, 16) == FAIL)
404ff6b5
AH
9508 goto fail_ldst;
9509
6c43fab6 9510 if (skip_past_comma (&str) == SUCCESS)
404ff6b5
AH
9511 {
9512 /* You are here: "<offset>]{!}". */
9513 inst.instruction |= PRE_INDEX;
9514
63e63b07 9515 offset = mav_parse_offset (&str, &negative);
404ff6b5
AH
9516
9517 if (inst.error)
9518 return;
9519
9520 if (*str++ != ']')
9521 {
9522 inst.error = _("missing ]");
9523 return;
9524 }
9525
9526 if (*str == '!')
9527 {
9528 inst.instruction |= WRITE_BACK;
9529 ++str;
9530 }
9531 }
9532 else
9533 {
9534 /* You are here: "], <offset>". */
9535 if (*str++ != ']')
9536 {
9537 inst.error = _("missing ]");
9538 return;
9539 }
9540
9541 if (skip_past_comma (&str) == FAIL
63e63b07 9542 || (offset = mav_parse_offset (&str, &negative), inst.error))
404ff6b5
AH
9543 goto fail_ldst;
9544
9545 inst.instruction |= CP_T_WB; /* Post indexed, set bit W. */
9546 }
9547
9548 if (negative)
9549 offset = -offset;
9550 else
9551 inst.instruction |= CP_T_UD; /* Postive, so set bit U. */
9552
9553 inst.instruction |= offset >> 2;
404ff6b5
AH
9554 end_of_line (str);
9555 return;
9556
9557fail_ldst:
9558 if (!inst.error)
9559 inst.error = BAD_ARGS;
9560 return;
9561}
9562
b99bd4ef
NC
9563static void
9564do_t_nop (str)
9565 char * str;
9566{
9567 /* Do nothing. */
9568 end_of_line (str);
9569 return;
9570}
9571
9572/* Handle the Format 4 instructions that do not have equivalents in other
9573 formats. That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
9574 BIC and MVN. */
9575
9576static void
9577do_t_arit (str)
9578 char * str;
9579{
9580 int Rd, Rs, Rn;
9581
9582 skip_whitespace (str);
9583
9584 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9585 || skip_past_comma (&str) == FAIL
9586 || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9587 {
9588 inst.error = BAD_ARGS;
9589 return;
9590 }
9591
9592 if (skip_past_comma (&str) != FAIL)
9593 {
9594 /* Three operand format not allowed for TST, CMN, NEG and MVN.
9595 (It isn't allowed for CMP either, but that isn't handled by this
9596 function.) */
9597 if (inst.instruction == T_OPCODE_TST
9598 || inst.instruction == T_OPCODE_CMN
9599 || inst.instruction == T_OPCODE_NEG
9600 || inst.instruction == T_OPCODE_MVN)
9601 {
9602 inst.error = BAD_ARGS;
9603 return;
9604 }
9605
9606 if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9607 return;
9608
9609 if (Rs != Rd)
9610 {
9611 inst.error = _("dest and source1 must be the same register");
9612 return;
9613 }
9614 Rs = Rn;
9615 }
9616
9617 if (inst.instruction == T_OPCODE_MUL
9618 && Rs == Rd)
9619 as_tsktsk (_("Rs and Rd must be different in MUL"));
9620
9621 inst.instruction |= Rd | (Rs << 3);
9622 end_of_line (str);
9623}
9624
9625static void
9626do_t_add (str)
9627 char * str;
9628{
9629 thumb_add_sub (str, 0);
9630}
9631
9632static void
9633do_t_asr (str)
9634 char * str;
9635{
9636 thumb_shift (str, THUMB_ASR);
9637}
9638
9639static void
9640do_t_branch9 (str)
9641 char * str;
9642{
9643 if (my_get_expression (&inst.reloc.exp, &str))
9644 return;
9645 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
9646 inst.reloc.pc_rel = 1;
9647 end_of_line (str);
9648}
9649
9650static void
9651do_t_branch12 (str)
9652 char * str;
9653{
9654 if (my_get_expression (&inst.reloc.exp, &str))
9655 return;
9656 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
9657 inst.reloc.pc_rel = 1;
9658 end_of_line (str);
9659}
9660
9661/* Find the real, Thumb encoded start of a Thumb function. */
9662
9663static symbolS *
9664find_real_start (symbolP)
9665 symbolS * symbolP;
9666{
9667 char * real_start;
9668 const char * name = S_GET_NAME (symbolP);
9669 symbolS * new_target;
9670
9671 /* This definiton must agree with the one in gcc/config/arm/thumb.c. */
9672#define STUB_NAME ".real_start_of"
9673
9674 if (name == NULL)
9675 abort ();
9676
9677 /* Names that start with '.' are local labels, not function entry points.
9678 The compiler may generate BL instructions to these labels because it
9679 needs to perform a branch to a far away location. */
9680 if (name[0] == '.')
9681 return symbolP;
9682
9683 real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1);
9684 sprintf (real_start, "%s%s", STUB_NAME, name);
9685
9686 new_target = symbol_find (real_start);
9687
9688 if (new_target == NULL)
9689 {
9690 as_warn ("Failed to find real start of function: %s\n", name);
9691 new_target = symbolP;
9692 }
9693
9694 free (real_start);
9695
9696 return new_target;
9697}
9698
9699static void
9700do_t_branch23 (str)
9701 char * str;
9702{
9703 if (my_get_expression (& inst.reloc.exp, & str))
9704 return;
9705
9706 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
9707 inst.reloc.pc_rel = 1;
9708 end_of_line (str);
9709
9710 /* If the destination of the branch is a defined symbol which does not have
9711 the THUMB_FUNC attribute, then we must be calling a function which has
9712 the (interfacearm) attribute. We look for the Thumb entry point to that
9713 function and change the branch to refer to that function instead. */
9714 if ( inst.reloc.exp.X_op == O_symbol
9715 && inst.reloc.exp.X_add_symbol != NULL
9716 && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
9717 && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
9718 inst.reloc.exp.X_add_symbol =
9719 find_real_start (inst.reloc.exp.X_add_symbol);
9720}
9721
9722static void
9723do_t_bx (str)
9724 char * str;
9725{
9726 int reg;
9727
9728 skip_whitespace (str);
9729
9730 if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
9731 return;
9732
9733 /* This sets THUMB_H2 from the top bit of reg. */
9734 inst.instruction |= reg << 3;
9735
9736 /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc
9737 should cause the alignment to be checked once it is known. This is
9738 because BX PC only works if the instruction is word aligned. */
9739
9740 end_of_line (str);
9741}
9742
9743static void
9744do_t_compare (str)
9745 char * str;
9746{
9747 thumb_mov_compare (str, THUMB_COMPARE);
9748}
9749
9750static void
9751do_t_ldmstm (str)
9752 char * str;
9753{
9754 int Rb;
9755 long range;
9756
9757 skip_whitespace (str);
9758
9759 if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9760 return;
9761
9762 if (*str != '!')
f03698e6 9763 as_warn (_("inserted missing '!': load/store multiple always writes back base register"));
b99bd4ef
NC
9764 else
9765 str++;
9766
9767 if (skip_past_comma (&str) == FAIL
9768 || (range = reg_list (&str)) == FAIL)
9769 {
9770 if (! inst.error)
9771 inst.error = BAD_ARGS;
9772 return;
9773 }
9774
9775 if (inst.reloc.type != BFD_RELOC_NONE)
9776 {
9777 /* This really doesn't seem worth it. */
9778 inst.reloc.type = BFD_RELOC_NONE;
f03698e6 9779 inst.error = _("expression too complex");
b99bd4ef
NC
9780 return;
9781 }
9782
9783 if (range & ~0xff)
9784 {
9785 inst.error = _("only lo-regs valid in load/store multiple");
9786 return;
9787 }
9788
9789 inst.instruction |= (Rb << 8) | range;
9790 end_of_line (str);
9791}
9792
9793static void
9794do_t_ldr (str)
9795 char * str;
9796{
9797 thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
9798}
9799
9800static void
9801do_t_ldrb (str)
9802 char * str;
9803{
9804 thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
9805}
9806
9807static void
9808do_t_ldrh (str)
9809 char * str;
9810{
9811 thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
9812}
9813
9814static void
9815do_t_lds (str)
9816 char * str;
9817{
9818 int Rd, Rb, Ro;
9819
9820 skip_whitespace (str);
9821
9822 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9823 || skip_past_comma (&str) == FAIL
9824 || *str++ != '['
9825 || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9826 || skip_past_comma (&str) == FAIL
9827 || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9828 || *str++ != ']')
9829 {
9830 if (! inst.error)
f03698e6 9831 inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]");
b99bd4ef
NC
9832 return;
9833 }
9834
9835 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
9836 end_of_line (str);
9837}
9838
9839static void
9840do_t_lsl (str)
9841 char * str;
9842{
9843 thumb_shift (str, THUMB_LSL);
9844}
9845
9846static void
9847do_t_lsr (str)
9848 char * str;
9849{
9850 thumb_shift (str, THUMB_LSR);
9851}
9852
9853static void
9854do_t_mov (str)
9855 char * str;
9856{
9857 thumb_mov_compare (str, THUMB_MOVE);
9858}
9859
9860static void
9861do_t_push_pop (str)
9862 char * str;
9863{
9864 long range;
9865
9866 skip_whitespace (str);
9867
9868 if ((range = reg_list (&str)) == FAIL)
9869 {
9870 if (! inst.error)
9871 inst.error = BAD_ARGS;
9872 return;
9873 }
9874
9875 if (inst.reloc.type != BFD_RELOC_NONE)
9876 {
9877 /* This really doesn't seem worth it. */
9878 inst.reloc.type = BFD_RELOC_NONE;
f03698e6 9879 inst.error = _("expression too complex");
b99bd4ef
NC
9880 return;
9881 }
9882
9883 if (range & ~0xff)
9884 {
9885 if ((inst.instruction == T_OPCODE_PUSH
9886 && (range & ~0xff) == 1 << REG_LR)
9887 || (inst.instruction == T_OPCODE_POP
9888 && (range & ~0xff) == 1 << REG_PC))
9889 {
9890 inst.instruction |= THUMB_PP_PC_LR;
9891 range &= 0xff;
9892 }
9893 else
9894 {
9895 inst.error = _("invalid register list to push/pop instruction");
9896 return;
9897 }
9898 }
9899
9900 inst.instruction |= range;
9901 end_of_line (str);
9902}
9903
9904static void
9905do_t_str (str)
9906 char * str;
9907{
9908 thumb_load_store (str, THUMB_STORE, THUMB_WORD);
9909}
9910
9911static void
9912do_t_strb (str)
9913 char * str;
9914{
9915 thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
9916}
9917
9918static void
9919do_t_strh (str)
9920 char * str;
9921{
9922 thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
9923}
9924
9925static void
9926do_t_sub (str)
9927 char * str;
9928{
9929 thumb_add_sub (str, 1);
9930}
9931
9932static void
9933do_t_swi (str)
9934 char * str;
9935{
9936 skip_whitespace (str);
9937
9938 if (my_get_expression (&inst.reloc.exp, &str))
9939 return;
9940
9941 inst.reloc.type = BFD_RELOC_ARM_SWI;
9942 end_of_line (str);
9943 return;
9944}
9945
9946static void
9947do_t_adr (str)
9948 char * str;
9949{
9950 int reg;
9951
9952 /* This is a pseudo-op of the form "adr rd, label" to be converted
9953 into a relative address of the form "add rd, pc, #label-.-4". */
9954 skip_whitespace (str);
9955
9956 /* Store Rd in temporary location inside instruction. */
9957 if ((reg = reg_required_here (&str, 4)) == FAIL
9958 || (reg > 7) /* For Thumb reg must be r0..r7. */
9959 || skip_past_comma (&str) == FAIL
9960 || my_get_expression (&inst.reloc.exp, &str))
9961 {
9962 if (!inst.error)
9963 inst.error = BAD_ARGS;
9964 return;
9965 }
9966
9967 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
9968 inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */
9969 inst.reloc.pc_rel = 1;
9970 inst.instruction |= REG_PC; /* Rd is already placed into the instruction. */
9971
9972 end_of_line (str);
9973}
9974
9975static void
6c43fab6
RE
9976insert_reg (r, htab)
9977 const struct reg_entry *r;
9978 struct hash_control *htab;
b99bd4ef 9979{
6c43fab6 9980 int len = strlen (r->name) + 2;
b99bd4ef
NC
9981 char * buf = (char *) xmalloc (len);
9982 char * buf2 = (char *) xmalloc (len);
9983 int i = 0;
9984
9985#ifdef REGISTER_PREFIX
9986 buf[i++] = REGISTER_PREFIX;
9987#endif
9988
6c43fab6 9989 strcpy (buf + i, r->name);
b99bd4ef
NC
9990
9991 for (i = 0; buf[i]; i++)
3882b010 9992 buf2[i] = TOUPPER (buf[i]);
b99bd4ef
NC
9993
9994 buf2[i] = '\0';
9995
6c43fab6
RE
9996 hash_insert (htab, buf, (PTR) r);
9997 hash_insert (htab, buf2, (PTR) r);
b99bd4ef
NC
9998}
9999
10000static void
6c43fab6
RE
10001build_reg_hsh (map)
10002 struct reg_map *map;
10003{
10004 const struct reg_entry *r;
10005
10006 if ((map->htab = hash_new ()) == NULL)
f03698e6 10007 as_fatal (_("virtual memory exhausted"));
6c43fab6
RE
10008
10009 for (r = map->names; r->name != NULL; r++)
10010 insert_reg (r, map->htab);
10011}
10012
10013static void
10014insert_reg_alias (str, regnum, htab)
b99bd4ef
NC
10015 char *str;
10016 int regnum;
6c43fab6 10017 struct hash_control *htab;
b99bd4ef
NC
10018{
10019 struct reg_entry *new =
10020 (struct reg_entry *) xmalloc (sizeof (struct reg_entry));
10021 char *name = xmalloc (strlen (str) + 1);
10022 strcpy (name, str);
10023
10024 new->name = name;
10025 new->number = regnum;
10026
6c43fab6 10027 hash_insert (htab, name, (PTR) new);
b99bd4ef
NC
10028}
10029
6c43fab6
RE
10030/* Look for the .req directive. This is of the form:
10031
10032 newname .req existing_name
10033
10034 If we find one, or if it looks sufficiently like one that we want to
10035 handle any error here, return non-zero. Otherwise return zero. */
10036static int
10037create_register_alias (newname, p)
10038 char *newname;
10039 char *p;
10040{
10041 char *q;
10042 char c;
10043
10044 q = p;
10045 skip_whitespace (q);
10046
10047 c = *p;
10048 *p = '\0';
10049
10050 if (*q && !strncmp (q, ".req ", 5))
10051 {
10052 char *copy_of_str;
10053 char *r;
10054
10055#ifdef IGNORE_OPCODE_CASE
10056 newname = original_case_string;
10057#endif
10058 copy_of_str = newname;
10059
10060 q += 4;
10061 skip_whitespace (q);
10062
10063 for (r = q; *r != '\0'; r++)
10064 if (*r == ' ')
10065 break;
10066
10067 if (r != q)
10068 {
10069 enum arm_reg_type new_type, old_type;
10070 int old_regno;
10071 char d = *r;
10072
10073 *r = '\0';
10074 old_type = arm_reg_parse_any (q);
10075 *r = d;
10076
10077 new_type = arm_reg_parse_any (newname);
10078
10079 if (new_type == REG_TYPE_MAX)
10080 {
10081 if (old_type != REG_TYPE_MAX)
10082 {
10083 old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab);
10084 insert_reg_alias (newname, old_regno,
10085 all_reg_maps[old_type].htab);
10086 }
10087 else
10088 as_warn (_("register '%s' does not exist\n"), q);
10089 }
10090 else if (old_type == REG_TYPE_MAX)
10091 {
10092 as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
10093 copy_of_str, q);
10094 }
10095 else
10096 {
10097 /* Do not warn about redefinitions to the same alias. */
10098 if (new_type != old_type
10099 || (arm_reg_parse (&q, all_reg_maps[old_type].htab)
10100 != arm_reg_parse (&q, all_reg_maps[new_type].htab)))
10101 as_warn (_("ignoring redefinition of register alias '%s'"),
10102 copy_of_str);
10103
10104 }
10105 }
10106 else
10107 as_warn (_("ignoring incomplete .req pseuso op"));
10108
10109 *p = c;
10110 return 1;
10111 }
10112 *p = c;
10113 return 0;
10114}
cc8a6dd0 10115
b99bd4ef
NC
10116static void
10117set_constant_flonums ()
10118{
10119 int i;
10120
10121 for (i = 0; i < NUM_FLOAT_VALS; i++)
10122 if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
10123 abort ();
10124}
10125
90e4755a
RE
10126/* Iterate over the base tables to create the instruction patterns. */
10127static void
10128build_arm_ops_hsh ()
10129{
10130 unsigned int i;
10131 unsigned int j;
10132 static struct obstack insn_obstack;
10133
10134 obstack_begin (&insn_obstack, 4000);
10135
10136 for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
10137 {
6c43fab6 10138 const struct asm_opcode *insn = insns + i;
90e4755a
RE
10139
10140 if (insn->cond_offset != 0)
10141 {
10142 /* Insn supports conditional execution. Build the varaints
10143 and insert them in the hash table. */
10144 for (j = 0; j < sizeof (conds) / sizeof (struct asm_cond); j++)
10145 {
10146 unsigned len = strlen (insn->template);
10147 struct asm_opcode *new;
10148 char *template;
10149
10150 new = obstack_alloc (&insn_obstack, sizeof (struct asm_opcode));
10151 /* All condition codes are two characters. */
10152 template = obstack_alloc (&insn_obstack, len + 3);
10153
10154 strncpy (template, insn->template, insn->cond_offset);
10155 strcpy (template + insn->cond_offset, conds[j].template);
10156 if (len > insn->cond_offset)
10157 strcpy (template + insn->cond_offset + 2,
10158 insn->template + insn->cond_offset);
10159 new->template = template;
10160 new->cond_offset = 0;
10161 new->variant = insn->variant;
10162 new->parms = insn->parms;
10163 new->value = (insn->value & ~COND_MASK) | conds[j].value;
10164
10165 hash_insert (arm_ops_hsh, new->template, (PTR) new);
10166 }
10167 }
10168 /* Finally, insert the unconditional insn in the table directly;
10169 no need to build a copy. */
10170 hash_insert (arm_ops_hsh, insn->template, (PTR) insn);
10171 }
10172}
10173
5a6c6817
NC
10174#if defined OBJ_ELF || defined OBJ_COFF
10175
10176#ifdef OBJ_ELF
10177#define arm_Note Elf_External_Note
10178#else
10179typedef struct
10180{
10181 unsigned char namesz[4]; /* Size of entry's owner string. */
10182 unsigned char descsz[4]; /* Size of the note descriptor. */
10183 unsigned char type[4]; /* Interpretation of the descriptor. */
10184 char name[1]; /* Start of the name+desc data. */
10185} arm_Note;
10186#endif
10187
10188/* The description is kept to a fix sized in order to make updating
10189 it and merging it easier. */
10190#define ARM_NOTE_DESCRIPTION_LENGTH 8
10191
10192static void
10193arm_add_note (name, description, type)
10194 const char * name;
10195 const char * description;
10196 unsigned int type;
10197{
10198 arm_Note note ATTRIBUTE_UNUSED;
10199 char * p;
10200 unsigned int name_len;
10201
10202 name_len = (strlen (name) + 1 + 3) & ~3;
10203
10204 p = frag_more (sizeof (note.namesz));
10205 md_number_to_chars (p, (valueT) name_len, sizeof (note.namesz));
10206
10207 p = frag_more (sizeof (note.descsz));
10208 md_number_to_chars (p, (valueT) ARM_NOTE_DESCRIPTION_LENGTH, sizeof (note.descsz));
10209
10210 p = frag_more (sizeof (note.type));
10211 md_number_to_chars (p, (valueT) type, sizeof (note.type));
10212
10213 p = frag_more (name_len);
10214 strcpy (p, name);
10215
10216 p = frag_more (ARM_NOTE_DESCRIPTION_LENGTH);
10217 strncpy (p, description, ARM_NOTE_DESCRIPTION_LENGTH);
10218 frag_align (2, 0, 0);
10219}
10220#endif
10221
b99bd4ef
NC
10222void
10223md_begin ()
10224{
10225 unsigned mach;
10226 unsigned int i;
10227
10228 if ( (arm_ops_hsh = hash_new ()) == NULL
10229 || (arm_tops_hsh = hash_new ()) == NULL
10230 || (arm_cond_hsh = hash_new ()) == NULL
10231 || (arm_shift_hsh = hash_new ()) == NULL
b99bd4ef 10232 || (arm_psr_hsh = hash_new ()) == NULL)
f03698e6 10233 as_fatal (_("virtual memory exhausted"));
b99bd4ef 10234
90e4755a 10235 build_arm_ops_hsh ();
b99bd4ef
NC
10236 for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++)
10237 hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i));
10238 for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
10239 hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
10240 for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
10241 hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
10242 for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
10243 hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
10244
6c43fab6
RE
10245 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
10246 build_reg_hsh (all_reg_maps + i);
b99bd4ef
NC
10247
10248 set_constant_flonums ();
10249
03b1477f
RE
10250 /* Set the cpu variant based on the command-line options. We prefer
10251 -mcpu= over -march= if both are set (as for GCC); and we prefer
10252 -mfpu= over any other way of setting the floating point unit.
10253 Use of legacy options with new options are faulted. */
10254 if (legacy_cpu != -1)
10255 {
10256 if (mcpu_cpu_opt != -1 || march_cpu_opt != -1)
10257 as_bad (_("use of old and new-style options to set CPU type"));
10258
10259 mcpu_cpu_opt = legacy_cpu;
10260 }
10261 else if (mcpu_cpu_opt == -1)
10262 mcpu_cpu_opt = march_cpu_opt;
10263
10264 if (legacy_fpu != -1)
10265 {
10266 if (mfpu_opt != -1)
10267 as_bad (_("use of old and new-style options to set FPU type"));
10268
10269 mfpu_opt = legacy_fpu;
10270 }
10271 else if (mfpu_opt == -1)
10272 {
39c2da32
RE
10273#if !(defined (TE_LINUX) || defined (TE_NetBSD))
10274 /* Some environments specify a default FPU. If they don't, infer it
10275 from the processor. */
03b1477f
RE
10276 if (mcpu_fpu_opt != -1)
10277 mfpu_opt = mcpu_fpu_opt;
10278 else
10279 mfpu_opt = march_fpu_opt;
39c2da32
RE
10280#else
10281 mfpu_opt = FPU_DEFAULT;
10282#endif
03b1477f
RE
10283 }
10284
10285 if (mfpu_opt == -1)
10286 {
10287 if (mcpu_cpu_opt == -1)
10288 mfpu_opt = FPU_DEFAULT;
10289 else if (mcpu_cpu_opt & ARM_EXT_V5)
10290 mfpu_opt = FPU_ARCH_VFP_V2;
10291 else
10292 mfpu_opt = FPU_ARCH_FPA;
10293 }
10294
10295 if (mcpu_cpu_opt == -1)
10296 mcpu_cpu_opt = CPU_DEFAULT;
10297
10298 cpu_variant = mcpu_cpu_opt | mfpu_opt;
10299
b99bd4ef
NC
10300#if defined OBJ_COFF || defined OBJ_ELF
10301 {
10302 unsigned int flags = 0;
10303
10304 /* Set the flags in the private structure. */
10305 if (uses_apcs_26) flags |= F_APCS26;
10306 if (support_interwork) flags |= F_INTERWORK;
10307 if (uses_apcs_float) flags |= F_APCS_FLOAT;
10308 if (pic_code) flags |= F_PIC;
bfae80f2 10309 if ((cpu_variant & FPU_ANY) == FPU_NONE
03b1477f 10310 || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only. */
bfae80f2 10311 flags |= F_SOFT_FLOAT;
03b1477f
RE
10312 /* Using VFP conventions (even if soft-float). */
10313 if (cpu_variant & FPU_VFP_EXT_NONE) flags |= F_VFP_FLOAT;
10314
fde78edd
NC
10315#if defined OBJ_ELF
10316 if (cpu_variant & ARM_CEXT_MAVERICK)
10317 {
10318 flags ^= F_SOFT_FLOAT;
10319 flags |= EF_ARM_MAVERICK_FLOAT;
10320 }
10321#endif
b99bd4ef
NC
10322
10323 bfd_set_private_flags (stdoutput, flags);
10324
10325 /* We have run out flags in the COFF header to encode the
10326 status of ATPCS support, so instead we create a dummy,
10327 empty, debug section called .arm.atpcs. */
10328 if (atpcs)
10329 {
10330 asection * sec;
10331
10332 sec = bfd_make_section (stdoutput, ".arm.atpcs");
10333
10334 if (sec != NULL)
10335 {
10336 bfd_set_section_flags
10337 (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
10338 bfd_set_section_size (stdoutput, sec, 0);
10339 bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
10340 }
10341 }
10342 }
10343#endif
10344
10345 /* Record the CPU type as well. */
10346 switch (cpu_variant & ARM_CPU_MASK)
10347 {
10348 case ARM_2:
10349 mach = bfd_mach_arm_2;
10350 break;
10351
10352 case ARM_3: /* Also ARM_250. */
10353 mach = bfd_mach_arm_2a;
10354 break;
10355
b89dddec
RE
10356 case ARM_6: /* Also ARM_7. */
10357 mach = bfd_mach_arm_3;
10358 break;
10359
b99bd4ef 10360 default:
5a6c6817 10361 mach = bfd_mach_arm_unknown;
b99bd4ef 10362 break;
b99bd4ef
NC
10363 }
10364
10365 /* Catch special cases. */
e16bb312
NC
10366 if (cpu_variant & ARM_CEXT_IWMMXT)
10367 mach = bfd_mach_arm_iWMMXt;
10368 else if (cpu_variant & ARM_CEXT_XSCALE)
b99bd4ef 10369 mach = bfd_mach_arm_XScale;
fde78edd
NC
10370 else if (cpu_variant & ARM_CEXT_MAVERICK)
10371 mach = bfd_mach_arm_ep9312;
b99bd4ef
NC
10372 else if (cpu_variant & ARM_EXT_V5E)
10373 mach = bfd_mach_arm_5TE;
10374 else if (cpu_variant & ARM_EXT_V5)
10375 {
b89dddec 10376 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
10377 mach = bfd_mach_arm_5T;
10378 else
10379 mach = bfd_mach_arm_5;
10380 }
b89dddec 10381 else if (cpu_variant & ARM_EXT_V4)
b99bd4ef 10382 {
b89dddec 10383 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
10384 mach = bfd_mach_arm_4T;
10385 else
10386 mach = bfd_mach_arm_4;
10387 }
b89dddec 10388 else if (cpu_variant & ARM_EXT_V3M)
b99bd4ef
NC
10389 mach = bfd_mach_arm_3M;
10390
5a6c6817 10391#if 0 /* Suppressed - for now. */
e16bb312 10392#if defined (OBJ_ELF) || defined (OBJ_COFF)
5a6c6817
NC
10393
10394 /* Create a .note section to fully identify this arm binary. */
10395
10396#define NOTE_ARCH_STRING "arch: "
10397
10398#if defined OBJ_COFF && ! defined NT_VERSION
10399#define NT_VERSION 1
10400#define NT_ARCH 2
10401#endif
10402
e16bb312 10403 {
e16bb312
NC
10404 segT current_seg = now_seg;
10405 subsegT current_subseg = now_subseg;
10406 asection * arm_arch;
5a6c6817
NC
10407 const char * arch_string;
10408
e16bb312
NC
10409 arm_arch = bfd_make_section_old_way (stdoutput, ARM_NOTE_SECTION);
10410
10411#ifdef OBJ_COFF
10412 bfd_set_section_flags (stdoutput, arm_arch,
10413 SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_LINK_ONCE \
10414 | SEC_HAS_CONTENTS);
10415#endif
10416 arm_arch->output_section = arm_arch;
10417 subseg_set (arm_arch, 0);
e16bb312 10418
5a6c6817
NC
10419 switch (mach)
10420 {
10421 default:
10422 case bfd_mach_arm_unknown: arch_string = "unknown"; break;
10423 case bfd_mach_arm_2: arch_string = "armv2"; break;
10424 case bfd_mach_arm_2a: arch_string = "armv2a"; break;
10425 case bfd_mach_arm_3: arch_string = "armv3"; break;
10426 case bfd_mach_arm_3M: arch_string = "armv3M"; break;
10427 case bfd_mach_arm_4: arch_string = "armv4"; break;
10428 case bfd_mach_arm_4T: arch_string = "armv4t"; break;
10429 case bfd_mach_arm_5: arch_string = "armv5"; break;
10430 case bfd_mach_arm_5T: arch_string = "armv5t"; break;
10431 case bfd_mach_arm_5TE: arch_string = "armv5te"; break;
10432 case bfd_mach_arm_XScale: arch_string = "XScale"; break;
10433 case bfd_mach_arm_ep9312: arch_string = "ep9312"; break;
10434 case bfd_mach_arm_iWMMXt: arch_string = "iWMMXt"; break;
10435 }
10436
10437 arm_add_note (NOTE_ARCH_STRING, arch_string, NT_ARCH);
e16bb312
NC
10438
10439 subseg_set (current_seg, current_subseg);
10440 }
10441#endif
5a6c6817
NC
10442#endif /* Suppressed code. */
10443
b99bd4ef
NC
10444 bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
10445}
10446
10447/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
10448 for use in the a.out file, and stores them in the array pointed to by buf.
10449 This knows about the endian-ness of the target machine and does
10450 THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
10451 2 (short) and 4 (long) Floating numbers are put out as a series of
10452 LITTLENUMS (shorts, here at least). */
10453
10454void
10455md_number_to_chars (buf, val, n)
10456 char * buf;
10457 valueT val;
10458 int n;
10459{
10460 if (target_big_endian)
10461 number_to_chars_bigendian (buf, val, n);
10462 else
10463 number_to_chars_littleendian (buf, val, n);
10464}
10465
10466static valueT
10467md_chars_to_number (buf, n)
10468 char * buf;
10469 int n;
10470{
10471 valueT result = 0;
10472 unsigned char * where = (unsigned char *) buf;
10473
10474 if (target_big_endian)
10475 {
10476 while (n--)
10477 {
10478 result <<= 8;
10479 result |= (*where++ & 255);
10480 }
10481 }
10482 else
10483 {
10484 while (n--)
10485 {
10486 result <<= 8;
10487 result |= (where[n] & 255);
10488 }
10489 }
10490
10491 return result;
10492}
10493
10494/* Turn a string in input_line_pointer into a floating point constant
10495 of type TYPE, and store the appropriate bytes in *LITP. The number
10496 of LITTLENUMS emitted is stored in *SIZEP. An error message is
10497 returned, or NULL on OK.
10498
10499 Note that fp constants aren't represent in the normal way on the ARM.
10500 In big endian mode, things are as expected. However, in little endian
10501 mode fp constants are big-endian word-wise, and little-endian byte-wise
10502 within the words. For example, (double) 1.1 in big endian mode is
10503 the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
10504 the byte sequence 99 99 f1 3f 9a 99 99 99.
10505
10506 ??? The format of 12 byte floats is uncertain according to gcc's arm.h. */
10507
10508char *
10509md_atof (type, litP, sizeP)
10510 char type;
10511 char * litP;
10512 int * sizeP;
10513{
10514 int prec;
10515 LITTLENUM_TYPE words[MAX_LITTLENUMS];
10516 char *t;
10517 int i;
10518
10519 switch (type)
10520 {
10521 case 'f':
10522 case 'F':
10523 case 's':
10524 case 'S':
10525 prec = 2;
10526 break;
10527
10528 case 'd':
10529 case 'D':
10530 case 'r':
10531 case 'R':
10532 prec = 4;
10533 break;
10534
10535 case 'x':
10536 case 'X':
10537 prec = 6;
10538 break;
10539
10540 case 'p':
10541 case 'P':
10542 prec = 6;
10543 break;
10544
10545 default:
10546 *sizeP = 0;
f03698e6 10547 return _("bad call to MD_ATOF()");
b99bd4ef
NC
10548 }
10549
10550 t = atof_ieee (input_line_pointer, type, words);
10551 if (t)
10552 input_line_pointer = t;
10553 *sizeP = prec * 2;
10554
10555 if (target_big_endian)
10556 {
10557 for (i = 0; i < prec; i++)
10558 {
10559 md_number_to_chars (litP, (valueT) words[i], 2);
10560 litP += 2;
10561 }
10562 }
10563 else
10564 {
bfae80f2
RE
10565 if (cpu_variant & FPU_ARCH_VFP)
10566 for (i = prec - 1; i >= 0; i--)
10567 {
10568 md_number_to_chars (litP, (valueT) words[i], 2);
10569 litP += 2;
10570 }
10571 else
10572 /* For a 4 byte float the order of elements in `words' is 1 0.
10573 For an 8 byte float the order is 1 0 3 2. */
10574 for (i = 0; i < prec; i += 2)
10575 {
10576 md_number_to_chars (litP, (valueT) words[i + 1], 2);
10577 md_number_to_chars (litP + 2, (valueT) words[i], 2);
10578 litP += 4;
10579 }
b99bd4ef
NC
10580 }
10581
10582 return 0;
10583}
10584
10585/* The knowledge of the PC's pipeline offset is built into the insns
10586 themselves. */
10587
10588long
10589md_pcrel_from (fixP)
10590 fixS * fixP;
10591{
10592 if (fixP->fx_addsy
10593 && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
10594 && fixP->fx_subsy == NULL)
10595 return 0;
10596
10597 if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD))
10598 {
10599 /* PC relative addressing on the Thumb is slightly odd
10600 as the bottom two bits of the PC are forced to zero
10601 for the calculation. */
10602 return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
10603 }
10604
10605#ifdef TE_WINCE
10606 /* The pattern was adjusted to accomodate CE's off-by-one fixups,
10607 so we un-adjust here to compensate for the accomodation. */
10608 return fixP->fx_where + fixP->fx_frag->fr_address + 8;
10609#else
10610 return fixP->fx_where + fixP->fx_frag->fr_address;
10611#endif
10612}
10613
10614/* Round up a section size to the appropriate boundary. */
10615
10616valueT
10617md_section_align (segment, size)
10618 segT segment ATTRIBUTE_UNUSED;
10619 valueT size;
10620{
10621#ifdef OBJ_ELF
10622 return size;
10623#else
10624 /* Round all sects to multiple of 4. */
10625 return (size + 3) & ~3;
10626#endif
10627}
10628
10629/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
10630 Otherwise we have no need to default values of symbols. */
10631
10632symbolS *
10633md_undefined_symbol (name)
10634 char * name ATTRIBUTE_UNUSED;
10635{
10636#ifdef OBJ_ELF
10637 if (name[0] == '_' && name[1] == 'G'
10638 && streq (name, GLOBAL_OFFSET_TABLE_NAME))
10639 {
10640 if (!GOT_symbol)
10641 {
10642 if (symbol_find (name))
10643 as_bad ("GOT already in the symbol table");
10644
10645 GOT_symbol = symbol_new (name, undefined_section,
10646 (valueT) 0, & zero_address_frag);
10647 }
10648
10649 return GOT_symbol;
10650 }
10651#endif
10652
10653 return 0;
10654}
10655
10656/* arm_reg_parse () := if it looks like a register, return its token and
10657 advance the pointer. */
10658
10659static int
6c43fab6 10660arm_reg_parse (ccp, htab)
b99bd4ef 10661 register char ** ccp;
6c43fab6 10662 struct hash_control *htab;
b99bd4ef
NC
10663{
10664 char * start = * ccp;
10665 char c;
10666 char * p;
10667 struct reg_entry * reg;
10668
10669#ifdef REGISTER_PREFIX
10670 if (*start != REGISTER_PREFIX)
10671 return FAIL;
10672 p = start + 1;
10673#else
10674 p = start;
10675#ifdef OPTIONAL_REGISTER_PREFIX
10676 if (*p == OPTIONAL_REGISTER_PREFIX)
10677 p++, start++;
10678#endif
10679#endif
3882b010 10680 if (!ISALPHA (*p) || !is_name_beginner (*p))
b99bd4ef
NC
10681 return FAIL;
10682
10683 c = *p++;
3882b010 10684 while (ISALPHA (c) || ISDIGIT (c) || c == '_')
b99bd4ef
NC
10685 c = *p++;
10686
10687 *--p = 0;
6c43fab6 10688 reg = (struct reg_entry *) hash_find (htab, start);
b99bd4ef
NC
10689 *p = c;
10690
10691 if (reg)
10692 {
10693 *ccp = p;
10694 return reg->number;
10695 }
10696
10697 return FAIL;
10698}
10699
6c43fab6
RE
10700/* Search for the following register name in each of the possible reg name
10701 tables. Return the classification if found, or REG_TYPE_MAX if not
10702 present. */
10703static enum arm_reg_type
10704arm_reg_parse_any (cp)
10705 char *cp;
10706{
10707 int i;
10708
10709 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
10710 if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL)
10711 return (enum arm_reg_type) i;
10712
10713 return REG_TYPE_MAX;
10714}
10715
94f592af
NC
10716void
10717md_apply_fix3 (fixP, valP, seg)
b99bd4ef 10718 fixS * fixP;
94f592af 10719 valueT * valP;
b99bd4ef
NC
10720 segT seg;
10721{
94f592af 10722 offsetT value = * valP;
b99bd4ef
NC
10723 offsetT newval;
10724 unsigned int newimm;
10725 unsigned long temp;
10726 int sign;
10727 char * buf = fixP->fx_where + fixP->fx_frag->fr_literal;
10728 arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data;
10729
10730 assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
10731
10732 /* Note whether this will delete the relocation. */
10733#if 0
10734 /* Patch from REarnshaw to JDavis (disabled for the moment, since it
10735 doesn't work fully.) */
10736 if ((fixP->fx_addsy == 0 || symbol_constant_p (fixP->fx_addsy))
10737 && !fixP->fx_pcrel)
10738#else
10739 if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
10740#endif
10741 fixP->fx_done = 1;
10742
10743 /* If this symbol is in a different section then we need to leave it for
10744 the linker to deal with. Unfortunately, md_pcrel_from can't tell,
10745 so we have to undo it's effects here. */
10746 if (fixP->fx_pcrel)
10747 {
10748 if (fixP->fx_addsy != NULL
10749 && S_IS_DEFINED (fixP->fx_addsy)
10750 && S_GET_SEGMENT (fixP->fx_addsy) != seg)
10751 {
10752 if (target_oabi
10753 && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
10754 || fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
10755 ))
10756 value = 0;
10757 else
10758 value += md_pcrel_from (fixP);
10759 }
10760 }
10761
10762 /* Remember value for emit_reloc. */
10763 fixP->fx_addnumber = value;
10764
10765 switch (fixP->fx_r_type)
10766 {
10767 case BFD_RELOC_ARM_IMMEDIATE:
10768 newimm = validate_immediate (value);
10769 temp = md_chars_to_number (buf, INSN_SIZE);
10770
10771 /* If the instruction will fail, see if we can fix things up by
10772 changing the opcode. */
10773 if (newimm == (unsigned int) FAIL
10774 && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
10775 {
10776 as_bad_where (fixP->fx_file, fixP->fx_line,
10777 _("invalid constant (%lx) after fixup"),
10778 (unsigned long) value);
10779 break;
10780 }
10781
10782 newimm |= (temp & 0xfffff000);
10783 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
6189168b 10784 fixP->fx_done = 1;
b99bd4ef
NC
10785 break;
10786
10787 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
10788 {
10789 unsigned int highpart = 0;
10790 unsigned int newinsn = 0xe1a00000; /* nop. */
6189168b 10791
b99bd4ef
NC
10792 newimm = validate_immediate (value);
10793 temp = md_chars_to_number (buf, INSN_SIZE);
10794
10795 /* If the instruction will fail, see if we can fix things up by
10796 changing the opcode. */
10797 if (newimm == (unsigned int) FAIL
10798 && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
10799 {
10800 /* No ? OK - try using two ADD instructions to generate
10801 the value. */
10802 newimm = validate_immediate_twopart (value, & highpart);
10803
10804 /* Yes - then make sure that the second instruction is
10805 also an add. */
10806 if (newimm != (unsigned int) FAIL)
10807 newinsn = temp;
10808 /* Still No ? Try using a negated value. */
10809 else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
10810 temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
10811 /* Otherwise - give up. */
10812 else
10813 {
10814 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10815 _("unable to compute ADRL instructions for PC offset of 0x%lx"),
08df2379 10816 (long) value);
b99bd4ef
NC
10817 break;
10818 }
10819
10820 /* Replace the first operand in the 2nd instruction (which
10821 is the PC) with the destination register. We have
10822 already added in the PC in the first instruction and we
10823 do not want to do it again. */
10824 newinsn &= ~ 0xf0000;
10825 newinsn |= ((newinsn & 0x0f000) << 4);
10826 }
10827
10828 newimm |= (temp & 0xfffff000);
10829 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
10830
10831 highpart |= (newinsn & 0xfffff000);
10832 md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
10833 }
10834 break;
10835
10836 case BFD_RELOC_ARM_OFFSET_IMM:
10837 sign = value >= 0;
10838
10839 if (value < 0)
10840 value = - value;
10841
10842 if (validate_offset_imm (value, 0) == FAIL)
10843 {
10844 as_bad_where (fixP->fx_file, fixP->fx_line,
10845 _("bad immediate value for offset (%ld)"),
10846 (long) value);
10847 break;
10848 }
10849
10850 newval = md_chars_to_number (buf, INSN_SIZE);
10851 newval &= 0xff7ff000;
10852 newval |= value | (sign ? INDEX_UP : 0);
10853 md_number_to_chars (buf, newval, INSN_SIZE);
10854 break;
10855
10856 case BFD_RELOC_ARM_OFFSET_IMM8:
10857 case BFD_RELOC_ARM_HWLITERAL:
10858 sign = value >= 0;
10859
10860 if (value < 0)
10861 value = - value;
10862
10863 if (validate_offset_imm (value, 1) == FAIL)
10864 {
10865 if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
10866 as_bad_where (fixP->fx_file, fixP->fx_line,
10867 _("invalid literal constant: pool needs to be closer"));
10868 else
10869 as_bad (_("bad immediate value for half-word offset (%ld)"),
10870 (long) value);
10871 break;
10872 }
10873
10874 newval = md_chars_to_number (buf, INSN_SIZE);
10875 newval &= 0xff7ff0f0;
10876 newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
10877 md_number_to_chars (buf, newval, INSN_SIZE);
10878 break;
10879
10880 case BFD_RELOC_ARM_LITERAL:
10881 sign = value >= 0;
10882
10883 if (value < 0)
10884 value = - value;
10885
10886 if (validate_offset_imm (value, 0) == FAIL)
10887 {
10888 as_bad_where (fixP->fx_file, fixP->fx_line,
10889 _("invalid literal constant: pool needs to be closer"));
10890 break;
10891 }
10892
10893 newval = md_chars_to_number (buf, INSN_SIZE);
10894 newval &= 0xff7ff000;
10895 newval |= value | (sign ? INDEX_UP : 0);
10896 md_number_to_chars (buf, newval, INSN_SIZE);
10897 break;
10898
10899 case BFD_RELOC_ARM_SHIFT_IMM:
10900 newval = md_chars_to_number (buf, INSN_SIZE);
10901 if (((unsigned long) value) > 32
10902 || (value == 32
10903 && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
10904 {
10905 as_bad_where (fixP->fx_file, fixP->fx_line,
10906 _("shift expression is too large"));
10907 break;
10908 }
10909
10910 if (value == 0)
10911 /* Shifts of zero must be done as lsl. */
10912 newval &= ~0x60;
10913 else if (value == 32)
10914 value = 0;
10915 newval &= 0xfffff07f;
10916 newval |= (value & 0x1f) << 7;
10917 md_number_to_chars (buf, newval, INSN_SIZE);
10918 break;
10919
10920 case BFD_RELOC_ARM_SWI:
10921 if (arm_data->thumb_mode)
10922 {
10923 if (((unsigned long) value) > 0xff)
10924 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10925 _("invalid swi expression"));
b99bd4ef
NC
10926 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
10927 newval |= value;
10928 md_number_to_chars (buf, newval, THUMB_SIZE);
10929 }
10930 else
10931 {
10932 if (((unsigned long) value) > 0x00ffffff)
10933 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10934 _("invalid swi expression"));
b99bd4ef
NC
10935 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
10936 newval |= value;
10937 md_number_to_chars (buf, newval, INSN_SIZE);
10938 }
10939 break;
10940
10941 case BFD_RELOC_ARM_MULTI:
10942 if (((unsigned long) value) > 0xffff)
10943 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10944 _("invalid expression in load/store multiple"));
b99bd4ef
NC
10945 newval = value | md_chars_to_number (buf, INSN_SIZE);
10946 md_number_to_chars (buf, newval, INSN_SIZE);
10947 break;
10948
10949 case BFD_RELOC_ARM_PCREL_BRANCH:
10950 newval = md_chars_to_number (buf, INSN_SIZE);
10951
10952 /* Sign-extend a 24-bit number. */
10953#define SEXT24(x) ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
10954
10955#ifdef OBJ_ELF
10956 if (! target_oabi)
10957 value = fixP->fx_offset;
10958#endif
10959
10960 /* We are going to store value (shifted right by two) in the
10961 instruction, in a 24 bit, signed field. Thus we need to check
10962 that none of the top 8 bits of the shifted value (top 7 bits of
10963 the unshifted, unsigned value) are set, or that they are all set. */
10964 if ((value & ~ ((offsetT) 0x1ffffff)) != 0
10965 && ((value & ~ ((offsetT) 0x1ffffff)) != ~ ((offsetT) 0x1ffffff)))
10966 {
10967#ifdef OBJ_ELF
10968 /* Normally we would be stuck at this point, since we cannot store
10969 the absolute address that is the destination of the branch in the
10970 24 bits of the branch instruction. If however, we happen to know
10971 that the destination of the branch is in the same section as the
10972 branch instruciton itself, then we can compute the relocation for
10973 ourselves and not have to bother the linker with it.
10974
10975 FIXME: The tests for OBJ_ELF and ! target_oabi are only here
10976 because I have not worked out how to do this for OBJ_COFF or
10977 target_oabi. */
10978 if (! target_oabi
10979 && fixP->fx_addsy != NULL
10980 && S_IS_DEFINED (fixP->fx_addsy)
10981 && S_GET_SEGMENT (fixP->fx_addsy) == seg)
10982 {
10983 /* Get pc relative value to go into the branch. */
94f592af 10984 value = * valP;
b99bd4ef
NC
10985
10986 /* Permit a backward branch provided that enough bits
10987 are set. Allow a forwards branch, provided that
10988 enough bits are clear. */
10989 if ( (value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff)
10990 || (value & ~ ((offsetT) 0x1ffffff)) == 0)
10991 fixP->fx_done = 1;
10992 }
10993
10994 if (! fixP->fx_done)
10995#endif
10996 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10997 _("GAS can't handle same-section branch dest >= 0x04000000"));
b99bd4ef
NC
10998 }
10999
11000 value >>= 2;
11001 value += SEXT24 (newval);
11002
11003 if ( (value & ~ ((offsetT) 0xffffff)) != 0
11004 && ((value & ~ ((offsetT) 0xffffff)) != ~ ((offsetT) 0xffffff)))
11005 as_bad_where (fixP->fx_file, fixP->fx_line,
11006 _("out of range branch"));
11007
11008 newval = (value & 0x00ffffff) | (newval & 0xff000000);
11009 md_number_to_chars (buf, newval, INSN_SIZE);
11010 break;
11011
11012 case BFD_RELOC_ARM_PCREL_BLX:
11013 {
11014 offsetT hbit;
11015 newval = md_chars_to_number (buf, INSN_SIZE);
11016
11017#ifdef OBJ_ELF
11018 if (! target_oabi)
11019 value = fixP->fx_offset;
11020#endif
11021 hbit = (value >> 1) & 1;
11022 value = (value >> 2) & 0x00ffffff;
11023 value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
11024 newval = value | (newval & 0xfe000000) | (hbit << 24);
11025 md_number_to_chars (buf, newval, INSN_SIZE);
11026 }
11027 break;
11028
11029 case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
11030 newval = md_chars_to_number (buf, THUMB_SIZE);
11031 {
11032 addressT diff = (newval & 0xff) << 1;
11033 if (diff & 0x100)
11034 diff |= ~0xff;
11035
11036 value += diff;
11037 if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
11038 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11039 _("branch out of range"));
b99bd4ef
NC
11040 newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
11041 }
11042 md_number_to_chars (buf, newval, THUMB_SIZE);
11043 break;
11044
11045 case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch. */
11046 newval = md_chars_to_number (buf, THUMB_SIZE);
11047 {
11048 addressT diff = (newval & 0x7ff) << 1;
11049 if (diff & 0x800)
11050 diff |= ~0x7ff;
11051
11052 value += diff;
11053 if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
11054 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11055 _("branch out of range"));
b99bd4ef
NC
11056 newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
11057 }
11058 md_number_to_chars (buf, newval, THUMB_SIZE);
11059 break;
11060
11061 case BFD_RELOC_THUMB_PCREL_BLX:
11062 case BFD_RELOC_THUMB_PCREL_BRANCH23:
11063 {
11064 offsetT newval2;
11065 addressT diff;
11066
11067 newval = md_chars_to_number (buf, THUMB_SIZE);
11068 newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
11069 diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
11070 if (diff & 0x400000)
11071 diff |= ~0x3fffff;
11072#ifdef OBJ_ELF
11073 value = fixP->fx_offset;
11074#endif
11075 value += diff;
c62e1cc3 11076
b99bd4ef
NC
11077 if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
11078 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11079 _("branch with link out of range"));
b99bd4ef
NC
11080
11081 newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
11082 newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
11083 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
c62e1cc3
NC
11084 /* For a BLX instruction, make sure that the relocation is rounded up
11085 to a word boundary. This follows the semantics of the instruction
11086 which specifies that bit 1 of the target address will come from bit
11087 1 of the base address. */
11088 newval2 = (newval2 + 1) & ~ 1;
b99bd4ef
NC
11089 md_number_to_chars (buf, newval, THUMB_SIZE);
11090 md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
11091 }
11092 break;
11093
11094 case BFD_RELOC_8:
11095 if (fixP->fx_done || fixP->fx_pcrel)
11096 md_number_to_chars (buf, value, 1);
11097#ifdef OBJ_ELF
11098 else if (!target_oabi)
11099 {
11100 value = fixP->fx_offset;
11101 md_number_to_chars (buf, value, 1);
11102 }
11103#endif
11104 break;
11105
11106 case BFD_RELOC_16:
11107 if (fixP->fx_done || fixP->fx_pcrel)
11108 md_number_to_chars (buf, value, 2);
11109#ifdef OBJ_ELF
11110 else if (!target_oabi)
11111 {
11112 value = fixP->fx_offset;
11113 md_number_to_chars (buf, value, 2);
11114 }
11115#endif
11116 break;
11117
11118#ifdef OBJ_ELF
11119 case BFD_RELOC_ARM_GOT32:
11120 case BFD_RELOC_ARM_GOTOFF:
11121 md_number_to_chars (buf, 0, 4);
11122 break;
11123#endif
11124
11125 case BFD_RELOC_RVA:
11126 case BFD_RELOC_32:
11127 if (fixP->fx_done || fixP->fx_pcrel)
11128 md_number_to_chars (buf, value, 4);
11129#ifdef OBJ_ELF
11130 else if (!target_oabi)
11131 {
11132 value = fixP->fx_offset;
11133 md_number_to_chars (buf, value, 4);
11134 }
11135#endif
11136 break;
11137
11138#ifdef OBJ_ELF
11139 case BFD_RELOC_ARM_PLT32:
11140 /* It appears the instruction is fully prepared at this point. */
11141 break;
11142#endif
11143
b99bd4ef
NC
11144 case BFD_RELOC_ARM_CP_OFF_IMM:
11145 sign = value >= 0;
11146 if (value < -1023 || value > 1023 || (value & 3))
11147 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11148 _("illegal value for co-processor offset"));
b99bd4ef
NC
11149 if (value < 0)
11150 value = -value;
11151 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
11152 newval |= (value >> 2) | (sign ? INDEX_UP : 0);
11153 md_number_to_chars (buf, newval, INSN_SIZE);
11154 break;
11155
e16bb312
NC
11156 case BFD_RELOC_ARM_CP_OFF_IMM_S2:
11157 sign = value >= 0;
11158 if (value < -255 || value > 255)
11159 as_bad_where (fixP->fx_file, fixP->fx_line,
11160 _("Illegal value for co-processor offset"));
11161 if (value < 0)
11162 value = -value;
11163 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
11164 newval |= value | (sign ? INDEX_UP : 0);
11165 md_number_to_chars (buf, newval , INSN_SIZE);
11166 break;
11167
b99bd4ef
NC
11168 case BFD_RELOC_ARM_THUMB_OFFSET:
11169 newval = md_chars_to_number (buf, THUMB_SIZE);
11170 /* Exactly what ranges, and where the offset is inserted depends
11171 on the type of instruction, we can establish this from the
11172 top 4 bits. */
11173 switch (newval >> 12)
11174 {
11175 case 4: /* PC load. */
11176 /* Thumb PC loads are somewhat odd, bit 1 of the PC is
11177 forced to zero for these loads, so we will need to round
11178 up the offset if the instruction address is not word
11179 aligned (since the final address produced must be, and
11180 we can only describe word-aligned immediate offsets). */
11181
11182 if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3)
11183 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11184 _("invalid offset, target not word aligned (0x%08X)"),
b99bd4ef
NC
11185 (unsigned int) (fixP->fx_frag->fr_address
11186 + fixP->fx_where + value));
11187
11188 if ((value + 2) & ~0x3fe)
11189 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11190 _("invalid offset, value too big (0x%08lX)"),
11191 (long) value);
b99bd4ef
NC
11192
11193 /* Round up, since pc will be rounded down. */
11194 newval |= (value + 2) >> 2;
11195 break;
11196
11197 case 9: /* SP load/store. */
11198 if (value & ~0x3fc)
11199 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11200 _("invalid offset, value too big (0x%08lX)"),
11201 (long) value);
b99bd4ef
NC
11202 newval |= value >> 2;
11203 break;
11204
11205 case 6: /* Word load/store. */
11206 if (value & ~0x7c)
11207 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11208 _("invalid offset, value too big (0x%08lX)"),
11209 (long) value);
b99bd4ef
NC
11210 newval |= value << 4; /* 6 - 2. */
11211 break;
11212
11213 case 7: /* Byte load/store. */
11214 if (value & ~0x1f)
11215 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11216 _("invalid offset, value too big (0x%08lX)"),
11217 (long) value);
b99bd4ef
NC
11218 newval |= value << 6;
11219 break;
11220
11221 case 8: /* Halfword load/store. */
11222 if (value & ~0x3e)
11223 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11224 _("invalid offset, value too big (0x%08lX)"),
11225 (long) value);
b99bd4ef
NC
11226 newval |= value << 5; /* 6 - 1. */
11227 break;
11228
11229 default:
11230 as_bad_where (fixP->fx_file, fixP->fx_line,
11231 "Unable to process relocation for thumb opcode: %lx",
11232 (unsigned long) newval);
11233 break;
11234 }
11235 md_number_to_chars (buf, newval, THUMB_SIZE);
11236 break;
11237
11238 case BFD_RELOC_ARM_THUMB_ADD:
11239 /* This is a complicated relocation, since we use it for all of
11240 the following immediate relocations:
11241
11242 3bit ADD/SUB
11243 8bit ADD/SUB
11244 9bit ADD/SUB SP word-aligned
11245 10bit ADD PC/SP word-aligned
11246
11247 The type of instruction being processed is encoded in the
11248 instruction field:
11249
11250 0x8000 SUB
11251 0x00F0 Rd
11252 0x000F Rs
11253 */
11254 newval = md_chars_to_number (buf, THUMB_SIZE);
11255 {
11256 int rd = (newval >> 4) & 0xf;
11257 int rs = newval & 0xf;
11258 int subtract = newval & 0x8000;
11259
11260 if (rd == REG_SP)
11261 {
11262 if (value & ~0x1fc)
11263 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11264 _("invalid immediate for stack address calculation"));
b99bd4ef
NC
11265 newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
11266 newval |= value >> 2;
11267 }
11268 else if (rs == REG_PC || rs == REG_SP)
11269 {
11270 if (subtract ||
11271 value & ~0x3fc)
11272 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11273 _("invalid immediate for address calculation (value = 0x%08lX)"),
b99bd4ef
NC
11274 (unsigned long) value);
11275 newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
11276 newval |= rd << 8;
11277 newval |= value >> 2;
11278 }
11279 else if (rs == rd)
11280 {
11281 if (value & ~0xff)
11282 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11283 _("invalid 8bit immediate"));
b99bd4ef
NC
11284 newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
11285 newval |= (rd << 8) | value;
11286 }
11287 else
11288 {
11289 if (value & ~0x7)
11290 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11291 _("invalid 3bit immediate"));
b99bd4ef
NC
11292 newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
11293 newval |= rd | (rs << 3) | (value << 6);
11294 }
11295 }
11296 md_number_to_chars (buf, newval, THUMB_SIZE);
11297 break;
11298
11299 case BFD_RELOC_ARM_THUMB_IMM:
11300 newval = md_chars_to_number (buf, THUMB_SIZE);
11301 switch (newval >> 11)
11302 {
11303 case 0x04: /* 8bit immediate MOV. */
11304 case 0x05: /* 8bit immediate CMP. */
11305 if (value < 0 || value > 255)
11306 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11307 _("invalid immediate: %ld is too large"),
b99bd4ef
NC
11308 (long) value);
11309 newval |= value;
11310 break;
11311
11312 default:
11313 abort ();
11314 }
11315 md_number_to_chars (buf, newval, THUMB_SIZE);
11316 break;
11317
11318 case BFD_RELOC_ARM_THUMB_SHIFT:
11319 /* 5bit shift value (0..31). */
11320 if (value < 0 || value > 31)
11321 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11322 _("illegal Thumb shift value: %ld"), (long) value);
b99bd4ef
NC
11323 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
11324 newval |= value << 6;
11325 md_number_to_chars (buf, newval, THUMB_SIZE);
11326 break;
11327
11328 case BFD_RELOC_VTABLE_INHERIT:
11329 case BFD_RELOC_VTABLE_ENTRY:
11330 fixP->fx_done = 0;
94f592af 11331 return;
b99bd4ef
NC
11332
11333 case BFD_RELOC_NONE:
11334 default:
11335 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11336 _("bad relocation fixup type (%d)"), fixP->fx_r_type);
b99bd4ef 11337 }
b99bd4ef
NC
11338}
11339
11340/* Translate internal representation of relocation info to BFD target
11341 format. */
11342
11343arelent *
11344tc_gen_reloc (section, fixp)
11345 asection * section ATTRIBUTE_UNUSED;
11346 fixS * fixp;
11347{
11348 arelent * reloc;
11349 bfd_reloc_code_real_type code;
11350
11351 reloc = (arelent *) xmalloc (sizeof (arelent));
11352
11353 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
11354 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
11355 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
11356
11357 /* @@ Why fx_addnumber sometimes and fx_offset other times? */
11358#ifndef OBJ_ELF
11359 if (fixp->fx_pcrel == 0)
11360 reloc->addend = fixp->fx_offset;
11361 else
11362 reloc->addend = fixp->fx_offset = reloc->address;
11363#else /* OBJ_ELF */
11364 reloc->addend = fixp->fx_offset;
11365#endif
11366
11367 switch (fixp->fx_r_type)
11368 {
11369 case BFD_RELOC_8:
11370 if (fixp->fx_pcrel)
11371 {
11372 code = BFD_RELOC_8_PCREL;
11373 break;
11374 }
11375
11376 case BFD_RELOC_16:
11377 if (fixp->fx_pcrel)
11378 {
11379 code = BFD_RELOC_16_PCREL;
11380 break;
11381 }
11382
11383 case BFD_RELOC_32:
11384 if (fixp->fx_pcrel)
11385 {
11386 code = BFD_RELOC_32_PCREL;
11387 break;
11388 }
11389
11390 case BFD_RELOC_ARM_PCREL_BRANCH:
11391 case BFD_RELOC_ARM_PCREL_BLX:
11392 case BFD_RELOC_RVA:
11393 case BFD_RELOC_THUMB_PCREL_BRANCH9:
11394 case BFD_RELOC_THUMB_PCREL_BRANCH12:
11395 case BFD_RELOC_THUMB_PCREL_BRANCH23:
11396 case BFD_RELOC_THUMB_PCREL_BLX:
11397 case BFD_RELOC_VTABLE_ENTRY:
11398 case BFD_RELOC_VTABLE_INHERIT:
11399 code = fixp->fx_r_type;
11400 break;
11401
11402 case BFD_RELOC_ARM_LITERAL:
11403 case BFD_RELOC_ARM_HWLITERAL:
3d0c9500
NC
11404 /* If this is called then the a literal has
11405 been referenced across a section boundary. */
b99bd4ef 11406 as_bad_where (fixp->fx_file, fixp->fx_line,
61b5f74b 11407 _("literal referenced across section boundary"));
b99bd4ef
NC
11408 return NULL;
11409
11410#ifdef OBJ_ELF
11411 case BFD_RELOC_ARM_GOT32:
11412 case BFD_RELOC_ARM_GOTOFF:
11413 case BFD_RELOC_ARM_PLT32:
11414 code = fixp->fx_r_type;
11415 break;
11416#endif
11417
11418 case BFD_RELOC_ARM_IMMEDIATE:
11419 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 11420 _("internal relocation (type: IMMEDIATE) not fixed up"));
b99bd4ef
NC
11421 return NULL;
11422
11423 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
11424 as_bad_where (fixp->fx_file, fixp->fx_line,
11425 _("ADRL used for a symbol not defined in the same file"));
11426 return NULL;
11427
11428 case BFD_RELOC_ARM_OFFSET_IMM:
11429 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 11430 _("internal_relocation (type: OFFSET_IMM) not fixed up"));
b99bd4ef
NC
11431 return NULL;
11432
11433 default:
11434 {
11435 char * type;
11436
11437 switch (fixp->fx_r_type)
11438 {
b99bd4ef
NC
11439 case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break;
11440 case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break;
11441 case BFD_RELOC_ARM_SWI: type = "SWI"; break;
11442 case BFD_RELOC_ARM_MULTI: type = "MULTI"; break;
11443 case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break;
11444 case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break;
11445 case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break;
11446 case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break;
11447 case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
11448 default: type = _("<unknown>"); break;
11449 }
11450 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 11451 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
11452 type);
11453 return NULL;
11454 }
11455 }
11456
11457#ifdef OBJ_ELF
8df7094c 11458 if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
b99bd4ef
NC
11459 && GOT_symbol
11460 && fixp->fx_addsy == GOT_symbol)
11461 {
11462 code = BFD_RELOC_ARM_GOTPC;
11463 reloc->addend = fixp->fx_offset = reloc->address;
11464 }
11465#endif
11466
11467 reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
11468
11469 if (reloc->howto == NULL)
11470 {
11471 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 11472 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
11473 bfd_get_reloc_code_name (code));
11474 return NULL;
11475 }
11476
11477 /* HACK: Since arm ELF uses Rel instead of Rela, encode the
11478 vtable entry to be used in the relocation's section offset. */
11479 if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
11480 reloc->address = fixp->fx_offset;
11481
11482 return reloc;
11483}
11484
11485int
11486md_estimate_size_before_relax (fragP, segtype)
11487 fragS * fragP ATTRIBUTE_UNUSED;
11488 segT segtype ATTRIBUTE_UNUSED;
11489{
11490 as_fatal (_("md_estimate_size_before_relax\n"));
11491 return 1;
11492}
11493
11494static void
f03698e6
RE
11495output_inst (str)
11496 const char *str;
b99bd4ef
NC
11497{
11498 char * to = NULL;
11499
11500 if (inst.error)
11501 {
f03698e6 11502 as_bad ("%s -- `%s'", inst.error, str);
b99bd4ef
NC
11503 return;
11504 }
11505
11506 to = frag_more (inst.size);
11507
11508 if (thumb_mode && (inst.size > THUMB_SIZE))
11509 {
11510 assert (inst.size == (2 * THUMB_SIZE));
11511 md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE);
11512 md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE);
11513 }
11514 else if (inst.size > INSN_SIZE)
11515 {
11516 assert (inst.size == (2 * INSN_SIZE));
11517 md_number_to_chars (to, inst.instruction, INSN_SIZE);
11518 md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
11519 }
11520 else
11521 md_number_to_chars (to, inst.instruction, inst.size);
11522
11523 if (inst.reloc.type != BFD_RELOC_NONE)
11524 fix_new_arm (frag_now, to - frag_now->fr_literal,
11525 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
11526 inst.reloc.type);
11527
11528#ifdef OBJ_ELF
11529 dwarf2_emit_insn (inst.size);
11530#endif
11531}
11532
11533void
11534md_assemble (str)
11535 char * str;
11536{
6c43fab6
RE
11537 char c;
11538 char *p;
11539 char *start;
b99bd4ef
NC
11540
11541 /* Align the instruction.
11542 This may not be the right thing to do but ... */
11543#if 0
11544 arm_align (2, 0);
11545#endif
b99bd4ef
NC
11546
11547 /* Align the previous label if needed. */
11548 if (last_label_seen != NULL)
11549 {
11550 symbol_set_frag (last_label_seen, frag_now);
11551 S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
11552 S_SET_SEGMENT (last_label_seen, now_seg);
11553 }
11554
11555 memset (&inst, '\0', sizeof (inst));
11556 inst.reloc.type = BFD_RELOC_NONE;
11557
11558 skip_whitespace (str);
11559
11560 /* Scan up to the end of the op-code, which must end in white space or
11561 end of string. */
11562 for (start = p = str; *p != '\0'; p++)
11563 if (*p == ' ')
11564 break;
11565
11566 if (p == str)
11567 {
f03698e6 11568 as_bad (_("no operator -- statement `%s'\n"), str);
b99bd4ef
NC
11569 return;
11570 }
11571
11572 if (thumb_mode)
11573 {
05d2d07e 11574 const struct thumb_opcode * opcode;
b99bd4ef
NC
11575
11576 c = *p;
11577 *p = '\0';
05d2d07e 11578 opcode = (const struct thumb_opcode *) hash_find (arm_tops_hsh, str);
b99bd4ef
NC
11579 *p = c;
11580
11581 if (opcode)
11582 {
11583 /* Check that this instruction is supported for this CPU. */
90e4755a 11584 if (thumb_mode == 1 && (opcode->variant & cpu_variant) == 0)
b99bd4ef 11585 {
f03698e6 11586 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
11587 return;
11588 }
11589
11590 inst.instruction = opcode->value;
11591 inst.size = opcode->size;
11592 (*opcode->parms) (p);
f03698e6 11593 output_inst (str);
b99bd4ef
NC
11594 return;
11595 }
11596 }
11597 else
11598 {
05d2d07e 11599 const struct asm_opcode * opcode;
b99bd4ef 11600
90e4755a
RE
11601 c = *p;
11602 *p = '\0';
6c43fab6 11603 opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, str);
90e4755a 11604 *p = c;
b99bd4ef 11605
90e4755a 11606 if (opcode)
b99bd4ef 11607 {
90e4755a
RE
11608 /* Check that this instruction is supported for this CPU. */
11609 if ((opcode->variant & cpu_variant) == 0)
b99bd4ef 11610 {
f03698e6 11611 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
11612 return;
11613 }
11614
90e4755a
RE
11615 inst.instruction = opcode->value;
11616 inst.size = INSN_SIZE;
f2b7cb0a 11617 (*opcode->parms) (p);
f03698e6 11618 output_inst (str);
90e4755a 11619 return;
b99bd4ef
NC
11620 }
11621 }
11622
11623 /* It wasn't an instruction, but it might be a register alias of the form
11624 alias .req reg. */
6c43fab6
RE
11625 if (create_register_alias (str, p))
11626 return;
b99bd4ef 11627
b99bd4ef
NC
11628 as_bad (_("bad instruction `%s'"), start);
11629}
11630
11631/* md_parse_option
11632 Invocation line includes a switch not recognized by the base assembler.
cc8a6dd0 11633 See if it's a processor-specific option.
03b1477f
RE
11634
11635 This routine is somewhat complicated by the need for backwards
11636 compatibility (since older releases of gcc can't be changed).
11637 The new options try to make the interface as compatible as
11638 possible with GCC.
11639
11640 New options (supported) are:
11641
11642 -mcpu=<cpu name> Assemble for selected processor
11643 -march=<architecture name> Assemble for selected architecture
11644 -mfpu=<fpu architecture> Assemble for selected FPU.
11645 -EB/-mbig-endian Big-endian
11646 -EL/-mlittle-endian Little-endian
11647 -k Generate PIC code
11648 -mthumb Start in Thumb mode
11649 -mthumb-interwork Code supports ARM/Thumb interworking
11650
3d0c9500 11651 For now we will also provide support for:
03b1477f
RE
11652
11653 -mapcs-32 32-bit Program counter
11654 -mapcs-26 26-bit Program counter
11655 -macps-float Floats passed in FP registers
11656 -mapcs-reentrant Reentrant code
11657 -matpcs
11658 (sometime these will probably be replaced with -mapcs=<list of options>
11659 and -matpcs=<list of options>)
11660
11661 The remaining options are only supported for back-wards compatibility.
b99bd4ef
NC
11662 Cpu variants, the arm part is optional:
11663 -m[arm]1 Currently not supported.
11664 -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor
11665 -m[arm]3 Arm 3 processor
11666 -m[arm]6[xx], Arm 6 processors
11667 -m[arm]7[xx][t][[d]m] Arm 7 processors
11668 -m[arm]8[10] Arm 8 processors
11669 -m[arm]9[20][tdmi] Arm 9 processors
11670 -mstrongarm[110[0]] StrongARM processors
11671 -mxscale XScale processors
11672 -m[arm]v[2345[t[e]]] Arm architectures
11673 -mall All (except the ARM1)
11674 FP variants:
11675 -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
11676 -mfpe-old (No float load/store multiples)
bfae80f2
RE
11677 -mvfpxd VFP Single precision
11678 -mvfp All VFP
b99bd4ef 11679 -mno-fpu Disable all floating point instructions
b99bd4ef 11680
03b1477f
RE
11681 The following CPU names are recognized:
11682 arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
11683 arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
11684 arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
11685 arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
11686 arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
11687 arm10t arm10e, arm1020t, arm1020e, arm10200e,
11688 strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
11689
11690 */
11691
5a38dc70 11692const char * md_shortopts = "m:k";
03b1477f 11693
b99bd4ef
NC
11694#ifdef ARM_BI_ENDIAN
11695#define OPTION_EB (OPTION_MD_BASE + 0)
b99bd4ef 11696#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 11697#else
21f0f23a
RE
11698#if TARGET_BYTES_BIG_ENDIAN
11699#define OPTION_EB (OPTION_MD_BASE + 0)
21f0f23a
RE
11700#else
11701#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 11702#endif
ce058b6c 11703#endif
03b1477f
RE
11704
11705struct option md_longopts[] =
11706{
11707#ifdef OPTION_EB
11708 {"EB", no_argument, NULL, OPTION_EB},
11709#endif
11710#ifdef OPTION_EL
11711 {"EL", no_argument, NULL, OPTION_EL},
b99bd4ef
NC
11712#endif
11713 {NULL, no_argument, NULL, 0}
11714};
11715
11716size_t md_longopts_size = sizeof (md_longopts);
11717
03b1477f 11718struct arm_option_table
b99bd4ef 11719{
03b1477f
RE
11720 char *option; /* Option name to match. */
11721 char *help; /* Help information. */
11722 int *var; /* Variable to change. */
11723 int value; /* What to change it to. */
11724 char *deprecated; /* If non-null, print this message. */
11725};
b99bd4ef 11726
cc8a6dd0 11727struct arm_option_table arm_opts[] =
03b1477f
RE
11728{
11729 {"k", N_("generate PIC code"), &pic_code, 1, NULL},
11730 {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL},
11731 {"mthumb-interwork", N_("support ARM/Thumb interworking"),
11732 &support_interwork, 1, NULL},
11733 {"moabi", N_("use old ABI (ELF only)"), &target_oabi, 1, NULL},
11734 {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
11735 {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
11736 {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
11737 1, NULL},
11738 {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
11739 {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
11740 {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
11741 {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 1,
11742 NULL},
11743
11744 /* These are recognized by the assembler, but have no affect on code. */
11745 {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
11746 {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
11747
11748 /* DON'T add any new processors to this list -- we want the whole list
11749 to go away... Add them to the processors table instead. */
11750 {"marm1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
11751 {"m1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
11752 {"marm2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
11753 {"m2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
11754 {"marm250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
11755 {"m250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
11756 {"marm3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
11757 {"m3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
11758 {"marm6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
11759 {"m6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
11760 {"marm600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
11761 {"m600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
11762 {"marm610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
11763 {"m610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
11764 {"marm620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
11765 {"m620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
11766 {"marm7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
11767 {"m7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
11768 {"marm70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
11769 {"m70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
11770 {"marm700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
11771 {"m700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
11772 {"marm700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
11773 {"m700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
11774 {"marm710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
11775 {"m710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
11776 {"marm710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
11777 {"m710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
11778 {"marm720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
11779 {"m720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
11780 {"marm7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
11781 {"m7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
11782 {"marm7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
11783 {"m7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
11784 {"marm7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
11785 {"m7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
11786 {"marm7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
11787 {"m7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
11788 {"marm7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
11789 {"m7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
11790 {"marm7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
11791 {"m7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
11792 {"marm7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
11793 {"m7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
11794 {"marm7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
11795 {"m7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
11796 {"marm7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11797 {"m7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11798 {"marm7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11799 {"m7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11800 {"marm710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
11801 {"m710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
11802 {"marm720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
11803 {"m720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
11804 {"marm740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
11805 {"m740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
11806 {"marm8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
11807 {"m8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
11808 {"marm810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
11809 {"m810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
11810 {"marm9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
11811 {"m9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
11812 {"marm9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
11813 {"m9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
11814 {"marm920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
11815 {"m920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
11816 {"marm940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
11817 {"m940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
11818 {"mstrongarm", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=strongarm")},
11819 {"mstrongarm110", NULL, &legacy_cpu, ARM_ARCH_V4,
11820 N_("use -mcpu=strongarm110")},
11821 {"mstrongarm1100", NULL, &legacy_cpu, ARM_ARCH_V4,
11822 N_("use -mcpu=strongarm1100")},
11823 {"mstrongarm1110", NULL, &legacy_cpu, ARM_ARCH_V4,
11824 N_("use -mcpu=strongarm1110")},
11825 {"mxscale", NULL, &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
e16bb312 11826 {"miwmmxt", NULL, &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
03b1477f
RE
11827 {"mall", NULL, &legacy_cpu, ARM_ANY, N_("use -mcpu=all")},
11828
11829 /* Architecture variants -- don't add any more to this list either. */
11830 {"mv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
11831 {"marmv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
11832 {"mv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
11833 {"marmv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
11834 {"mv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
11835 {"marmv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
11836 {"mv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
11837 {"marmv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
11838 {"mv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
11839 {"marmv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
11840 {"mv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
11841 {"marmv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
11842 {"mv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
11843 {"marmv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
11844 {"mv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
11845 {"marmv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
11846 {"mv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
11847 {"marmv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
11848
11849 /* Floating point variants -- don't add any more to this list either. */
11850 {"mfpe-old", NULL, &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
11851 {"mfpa10", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
11852 {"mfpa11", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
11853 {"mno-fpu", NULL, &legacy_fpu, 0,
11854 N_("use either -mfpu=softfpa or -mfpu=softvfp")},
11855
11856 {NULL, NULL, NULL, 0, NULL}
11857};
21f0f23a 11858
03b1477f
RE
11859struct arm_cpu_option_table
11860{
11861 char *name;
11862 int value;
11863 /* For some CPUs we assume an FPU unless the user explicitly sets
11864 -mfpu=... */
11865 int default_fpu;
11866};
11867
11868/* This list should, at a minimum, contain all the cpu names
11869 recognized by GCC. */
11870static struct arm_cpu_option_table arm_cpus[] =
11871{
11872 {"all", ARM_ANY, FPU_ARCH_FPA},
11873 {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA},
11874 {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA},
11875 {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA},
11876 {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA},
11877 {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA},
11878 {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA},
11879 {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA},
11880 {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA},
11881 {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA},
11882 {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA},
11883 {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA},
11884 {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA},
11885 {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA},
11886 {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA},
11887 {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA},
11888 {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA},
11889 {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA},
11890 {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA},
11891 {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA},
11892 {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11893 {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA},
11894 {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11895 {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11896 {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA},
11897 {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA},
11898 {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA},
11899 {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA},
11900 {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11901 {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
11902 {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA},
11903 {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA},
11904 {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA},
11905 {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA},
11906 {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA},
11907 {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA},
11908 {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA},
11909 {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA},
11910 {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA},
11911 {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11912 {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11913 {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11914 {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
11915 /* For V5 or later processors we default to using VFP; but the user
11916 should really set the FPU type explicitly. */
11917 {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
11918 {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
ea6ef066 11919 {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
03b1477f
RE
11920 {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
11921 {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11922 {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
11923 {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11924 {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
11925 {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11926 {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11927 {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
11928 {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11929 /* ??? XSCALE is really an architecture. */
11930 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
5a6c6817 11931 /* ??? iwmmxt is not a processor. */
e16bb312 11932 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2},
03b1477f
RE
11933 {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
11934 /* Maverick */
11935 {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_NONE},
11936 {NULL, 0, 0}
11937};
cc8a6dd0 11938
03b1477f
RE
11939struct arm_arch_option_table
11940{
11941 char *name;
11942 int value;
11943 int default_fpu;
11944};
11945
11946/* This list should, at a minimum, contain all the architecture names
11947 recognized by GCC. */
11948static struct arm_arch_option_table arm_archs[] =
11949{
11950 {"all", ARM_ANY, FPU_ARCH_FPA},
11951 {"armv1", ARM_ARCH_V1, FPU_ARCH_FPA},
11952 {"armv2", ARM_ARCH_V2, FPU_ARCH_FPA},
11953 {"armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA},
11954 {"armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA},
11955 {"armv3", ARM_ARCH_V3, FPU_ARCH_FPA},
11956 {"armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA},
11957 {"armv4", ARM_ARCH_V4, FPU_ARCH_FPA},
11958 {"armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA},
11959 {"armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11960 {"armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA},
11961 {"armv5", ARM_ARCH_V5, FPU_ARCH_VFP},
11962 {"armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP},
11963 {"armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP},
11964 {"armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP},
11965 {"armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP},
ea6ef066 11966 {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP},
03b1477f 11967 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP},
8266886e 11968 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
03b1477f
RE
11969 {NULL, 0, 0}
11970};
11971
11972/* ISA extensions in the co-processor space. */
11973struct arm_arch_extension_table
11974{
11975 char *name;
11976 int value;
11977};
11978
11979static struct arm_arch_extension_table arm_extensions[] =
11980{
11981 {"maverick", ARM_CEXT_MAVERICK},
11982 {"xscale", ARM_CEXT_XSCALE},
e16bb312 11983 {"iwmmxt", ARM_CEXT_IWMMXT},
03b1477f
RE
11984 {NULL, 0}
11985};
b99bd4ef 11986
03b1477f
RE
11987struct arm_fpu_option_table
11988{
11989 char *name;
11990 int value;
11991};
11992
11993/* This list should, at a minimum, contain all the fpu names
11994 recognized by GCC. */
11995static struct arm_fpu_option_table arm_fpus[] =
11996{
11997 {"softfpa", FPU_NONE},
11998 {"fpe", FPU_ARCH_FPE},
d193a22a
RE
11999 {"fpe2", FPU_ARCH_FPE},
12000 {"fpe3", FPU_ARCH_FPA}, /* Third release supports LFM/SFM. */
03b1477f
RE
12001 {"fpa", FPU_ARCH_FPA},
12002 {"fpa10", FPU_ARCH_FPA},
12003 {"fpa11", FPU_ARCH_FPA},
12004 {"arm7500fe", FPU_ARCH_FPA},
12005 {"softvfp", FPU_ARCH_VFP},
12006 {"softvfp+vfp", FPU_ARCH_VFP_V2},
12007 {"vfp", FPU_ARCH_VFP_V2},
12008 {"vfp9", FPU_ARCH_VFP_V2},
12009 {"vfp10", FPU_ARCH_VFP_V2},
12010 {"vfp10-r0", FPU_ARCH_VFP_V1},
12011 {"vfpxd", FPU_ARCH_VFP_V1xD},
12012 {"arm1020t", FPU_ARCH_VFP_V1},
12013 {"arm1020e", FPU_ARCH_VFP_V2},
12014 {NULL, 0}
12015};
12016
12017struct arm_long_option_table
12018{
12019 char *option; /* Substring to match. */
12020 char *help; /* Help information. */
12021 int (*func) PARAMS ((char *subopt)); /* Function to decode sub-option. */
12022 char *deprecated; /* If non-null, print this message. */
12023};
12024
12025static int
12026arm_parse_extension (str, opt_p)
12027 char *str;
12028 int *opt_p;
12029{
12030 while (str != NULL && *str != 0)
12031 {
12032 struct arm_arch_extension_table *opt;
12033 char *ext;
12034 int optlen;
12035
12036 if (*str != '+')
b99bd4ef 12037 {
03b1477f
RE
12038 as_bad (_("invalid architectural extension"));
12039 return 0;
12040 }
b99bd4ef 12041
03b1477f
RE
12042 str++;
12043 ext = strchr (str, '+');
b99bd4ef 12044
03b1477f
RE
12045 if (ext != NULL)
12046 optlen = ext - str;
12047 else
12048 optlen = strlen (str);
b99bd4ef 12049
03b1477f
RE
12050 if (optlen == 0)
12051 {
12052 as_bad (_("missing architectural extension"));
12053 return 0;
12054 }
b99bd4ef 12055
03b1477f
RE
12056 for (opt = arm_extensions; opt->name != NULL; opt++)
12057 if (strncmp (opt->name, str, optlen) == 0)
12058 {
12059 *opt_p |= opt->value;
12060 break;
12061 }
bfae80f2 12062
03b1477f
RE
12063 if (opt->name == NULL)
12064 {
12065 as_bad (_("unknown architectural extnsion `%s'"), str);
12066 return 0;
12067 }
b99bd4ef 12068
03b1477f
RE
12069 str = ext;
12070 };
b99bd4ef 12071
03b1477f
RE
12072 return 1;
12073}
b99bd4ef 12074
03b1477f
RE
12075static int
12076arm_parse_cpu (str)
12077 char *str;
12078{
12079 struct arm_cpu_option_table *opt;
12080 char *ext = strchr (str, '+');
12081 int optlen;
b99bd4ef 12082
03b1477f
RE
12083 if (ext != NULL)
12084 optlen = ext - str;
12085 else
12086 optlen = strlen (str);
b99bd4ef 12087
03b1477f
RE
12088 if (optlen == 0)
12089 {
12090 as_bad (_("missing cpu name `%s'"), str);
12091 return 0;
12092 }
b99bd4ef 12093
03b1477f
RE
12094 for (opt = arm_cpus; opt->name != NULL; opt++)
12095 if (strncmp (opt->name, str, optlen) == 0)
12096 {
12097 mcpu_cpu_opt = opt->value;
12098 mcpu_fpu_opt = opt->default_fpu;
b99bd4ef 12099
03b1477f
RE
12100 if (ext != NULL)
12101 return arm_parse_extension (ext, &mcpu_cpu_opt);
b99bd4ef 12102
03b1477f
RE
12103 return 1;
12104 }
b99bd4ef 12105
03b1477f
RE
12106 as_bad (_("unknown cpu `%s'"), str);
12107 return 0;
12108}
b99bd4ef 12109
03b1477f
RE
12110static int
12111arm_parse_arch (str)
12112 char *str;
12113{
12114 struct arm_arch_option_table *opt;
12115 char *ext = strchr (str, '+');
12116 int optlen;
b99bd4ef 12117
03b1477f
RE
12118 if (ext != NULL)
12119 optlen = ext - str;
12120 else
12121 optlen = strlen (str);
b99bd4ef 12122
03b1477f
RE
12123 if (optlen == 0)
12124 {
12125 as_bad (_("missing architecture name `%s'"), str);
12126 return 0;
12127 }
b99bd4ef 12128
b99bd4ef 12129
03b1477f
RE
12130 for (opt = arm_archs; opt->name != NULL; opt++)
12131 if (strcmp (opt->name, str) == 0)
12132 {
12133 march_cpu_opt = opt->value;
12134 march_fpu_opt = opt->default_fpu;
b99bd4ef 12135
03b1477f
RE
12136 if (ext != NULL)
12137 return arm_parse_extension (ext, &march_cpu_opt);
b99bd4ef 12138
03b1477f
RE
12139 return 1;
12140 }
b99bd4ef 12141
03b1477f
RE
12142 as_bad (_("unknown architecture `%s'\n"), str);
12143 return 0;
12144}
12145
12146static int
12147arm_parse_fpu (str)
12148 char *str;
12149{
12150 struct arm_fpu_option_table *opt;
b99bd4ef 12151
03b1477f
RE
12152 for (opt = arm_fpus; opt->name != NULL; opt++)
12153 if (strcmp (opt->name, str) == 0)
12154 {
12155 mfpu_opt = opt->value;
12156 return 1;
12157 }
b99bd4ef 12158
03b1477f
RE
12159 as_bad (_("unknown floating point format `%s'\n"), str);
12160 return 0;
12161}
b99bd4ef 12162
03b1477f
RE
12163struct arm_long_option_table arm_long_opts[] =
12164{
12165 {"mcpu=", N_("<cpu name>\t assemble for CPU <cpu name>"),
12166 arm_parse_cpu, NULL},
12167 {"march=", N_("<arch name>\t assemble for architecture <arch name>"),
12168 arm_parse_arch, NULL},
12169 {"mfpu=", N_("<fpu name>\t assemble for FPU architecture <fpu name>"),
12170 arm_parse_fpu, NULL},
12171 {NULL, NULL, 0, NULL}
12172};
b99bd4ef 12173
03b1477f
RE
12174int
12175md_parse_option (c, arg)
12176 int c;
12177 char * arg;
12178{
12179 struct arm_option_table *opt;
12180 struct arm_long_option_table *lopt;
b99bd4ef 12181
03b1477f
RE
12182 switch (c)
12183 {
12184#ifdef OPTION_EB
12185 case OPTION_EB:
12186 target_big_endian = 1;
b99bd4ef 12187 break;
03b1477f 12188#endif
b99bd4ef 12189
03b1477f
RE
12190#ifdef OPTION_EL
12191 case OPTION_EL:
12192 target_big_endian = 0;
b99bd4ef
NC
12193 break;
12194#endif
12195
03b1477f 12196 case 'a':
cc8a6dd0 12197 /* Listing option. Just ignore these, we don't support additional
03b1477f
RE
12198 ones. */
12199 return 0;
12200
b99bd4ef 12201 default:
03b1477f
RE
12202 for (opt = arm_opts; opt->option != NULL; opt++)
12203 {
12204 if (c == opt->option[0]
12205 && ((arg == NULL && opt->option[1] == 0)
12206 || strcmp (arg, opt->option + 1) == 0))
12207 {
12208#if WARN_DEPRECATED
12209 /* If the option is deprecated, tell the user. */
12210 if (opt->deprecated != NULL)
12211 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
12212 arg ? arg : "", _(opt->deprecated));
12213#endif
12214
12215 if (opt->var != NULL)
12216 *opt->var = opt->value;
12217
12218 return 1;
12219 }
12220 }
12221
12222 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
12223 {
cc8a6dd0 12224 /* These options are expected to have an argument. */
03b1477f
RE
12225 if (c == lopt->option[0]
12226 && arg != NULL
cc8a6dd0 12227 && strncmp (arg, lopt->option + 1,
03b1477f
RE
12228 strlen (lopt->option + 1)) == 0)
12229 {
12230#if WARN_DEPRECATED
12231 /* If the option is deprecated, tell the user. */
12232 if (lopt->deprecated != NULL)
12233 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
12234 _(lopt->deprecated));
12235#endif
12236
12237 /* Call the sup-option parser. */
12238 return (*lopt->func)(arg + strlen (lopt->option) - 1);
12239 }
12240 }
12241
12242 as_bad (_("unrecognized option `-%c%s'"), c, arg ? arg : "");
b99bd4ef
NC
12243 return 0;
12244 }
12245
12246 return 1;
12247}
12248
12249void
12250md_show_usage (fp)
12251 FILE * fp;
12252{
03b1477f
RE
12253 struct arm_option_table *opt;
12254 struct arm_long_option_table *lopt;
12255
12256 fprintf (fp, _(" ARM-specific assembler options:\n"));
12257
12258 for (opt = arm_opts; opt->option != NULL; opt++)
12259 if (opt->help != NULL)
12260 fprintf (fp, " -%-23s%s\n", opt->option, _(opt->help));
12261
12262 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
12263 if (lopt->help != NULL)
12264 fprintf (fp, " -%s%s\n", lopt->option, _(lopt->help));
12265
12266#ifdef OPTION_EB
b99bd4ef 12267 fprintf (fp, _("\
03b1477f 12268 -EB assemble code for a big-endian cpu\n"));
b99bd4ef 12269#endif
03b1477f
RE
12270
12271#ifdef OPTION_EL
b99bd4ef 12272 fprintf (fp, _("\
03b1477f 12273 -EL assemble code for a little-endian cpu\n"));
b99bd4ef
NC
12274#endif
12275}
12276
12277/* We need to be able to fix up arbitrary expressions in some statements.
12278 This is so that we can handle symbols that are an arbitrary distance from
12279 the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
12280 which returns part of an address in a form which will be valid for
12281 a data instruction. We do this by pushing the expression into a symbol
12282 in the expr_section, and creating a fix for that. */
12283
12284static void
12285fix_new_arm (frag, where, size, exp, pc_rel, reloc)
12286 fragS * frag;
12287 int where;
12288 short int size;
12289 expressionS * exp;
12290 int pc_rel;
12291 int reloc;
12292{
12293 fixS * new_fix;
12294 arm_fix_data * arm_data;
12295
12296 switch (exp->X_op)
12297 {
12298 case O_constant:
12299 case O_symbol:
12300 case O_add:
12301 case O_subtract:
12302 new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
12303 break;
12304
12305 default:
12306 new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
12307 pc_rel, reloc);
12308 break;
12309 }
12310
12311 /* Mark whether the fix is to a THUMB instruction, or an ARM
12312 instruction. */
12313 arm_data = (arm_fix_data *) obstack_alloc (& notes, sizeof (arm_fix_data));
12314 new_fix->tc_fix_data = (PTR) arm_data;
12315 arm_data->thumb_mode = thumb_mode;
12316
12317 return;
12318}
12319
12320/* This fix_new is called by cons via TC_CONS_FIX_NEW. */
12321
12322void
12323cons_fix_new_arm (frag, where, size, exp)
12324 fragS * frag;
12325 int where;
12326 int size;
12327 expressionS * exp;
12328{
12329 bfd_reloc_code_real_type type;
12330 int pcrel = 0;
12331
12332 /* Pick a reloc.
12333 FIXME: @@ Should look at CPU word size. */
12334 switch (size)
12335 {
12336 case 1:
12337 type = BFD_RELOC_8;
12338 break;
12339 case 2:
12340 type = BFD_RELOC_16;
12341 break;
12342 case 4:
12343 default:
12344 type = BFD_RELOC_32;
12345 break;
12346 case 8:
12347 type = BFD_RELOC_64;
12348 break;
12349 }
12350
12351 fix_new_exp (frag, where, (int) size, exp, pcrel, type);
12352}
12353
12354/* A good place to do this, although this was probably not intended
12355 for this kind of use. We need to dump the literal pool before
12356 references are made to a null symbol pointer. */
12357
12358void
12359arm_cleanup ()
12360{
3d0c9500 12361 literal_pool * pool;
b99bd4ef 12362
3d0c9500
NC
12363 for (pool = list_of_pools; pool; pool = pool->next)
12364 {
12365 /* Put it at the end of the relevent section. */
12366 subseg_set (pool->section, pool->sub_section);
12367 s_ltorg (0);
12368 }
b99bd4ef
NC
12369}
12370
12371void
12372arm_start_line_hook ()
12373{
12374 last_label_seen = NULL;
12375}
12376
12377void
12378arm_frob_label (sym)
12379 symbolS * sym;
12380{
12381 last_label_seen = sym;
12382
12383 ARM_SET_THUMB (sym, thumb_mode);
12384
12385#if defined OBJ_COFF || defined OBJ_ELF
12386 ARM_SET_INTERWORK (sym, support_interwork);
12387#endif
12388
12389 /* Note - do not allow local symbols (.Lxxx) to be labeled
12390 as Thumb functions. This is because these labels, whilst
12391 they exist inside Thumb code, are not the entry points for
12392 possible ARM->Thumb calls. Also, these labels can be used
12393 as part of a computed goto or switch statement. eg gcc
12394 can generate code that looks like this:
12395
12396 ldr r2, [pc, .Laaa]
12397 lsl r3, r3, #2
12398 ldr r2, [r3, r2]
12399 mov pc, r2
cc8a6dd0 12400
b99bd4ef
NC
12401 .Lbbb: .word .Lxxx
12402 .Lccc: .word .Lyyy
12403 ..etc...
12404 .Laaa: .word Lbbb
12405
12406 The first instruction loads the address of the jump table.
12407 The second instruction converts a table index into a byte offset.
12408 The third instruction gets the jump address out of the table.
12409 The fourth instruction performs the jump.
cc8a6dd0 12410
b99bd4ef
NC
12411 If the address stored at .Laaa is that of a symbol which has the
12412 Thumb_Func bit set, then the linker will arrange for this address
12413 to have the bottom bit set, which in turn would mean that the
12414 address computation performed by the third instruction would end
12415 up with the bottom bit set. Since the ARM is capable of unaligned
12416 word loads, the instruction would then load the incorrect address
12417 out of the jump table, and chaos would ensue. */
12418 if (label_is_thumb_function_name
12419 && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
12420 && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
12421 {
12422 /* When the address of a Thumb function is taken the bottom
12423 bit of that address should be set. This will allow
12424 interworking between Arm and Thumb functions to work
12425 correctly. */
12426
12427 THUMB_SET_FUNC (sym, 1);
12428
b34976b6 12429 label_is_thumb_function_name = FALSE;
b99bd4ef
NC
12430 }
12431}
12432
12433/* Adjust the symbol table. This marks Thumb symbols as distinct from
12434 ARM ones. */
12435
12436void
12437arm_adjust_symtab ()
12438{
12439#ifdef OBJ_COFF
12440 symbolS * sym;
12441
12442 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
12443 {
12444 if (ARM_IS_THUMB (sym))
12445 {
12446 if (THUMB_IS_FUNC (sym))
12447 {
12448 /* Mark the symbol as a Thumb function. */
12449 if ( S_GET_STORAGE_CLASS (sym) == C_STAT
12450 || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */
12451 S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
12452
12453 else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
12454 S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
12455 else
12456 as_bad (_("%s: unexpected function type: %d"),
12457 S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
12458 }
cc8a6dd0 12459 else switch (S_GET_STORAGE_CLASS (sym))
b99bd4ef
NC
12460 {
12461 case C_EXT:
12462 S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
12463 break;
12464 case C_STAT:
12465 S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
12466 break;
12467 case C_LABEL:
12468 S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
12469 break;
12470 default:
12471 /* Do nothing. */
12472 break;
12473 }
12474 }
12475
12476 if (ARM_IS_INTERWORK (sym))
12477 coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
12478 }
12479#endif
12480#ifdef OBJ_ELF
12481 symbolS * sym;
12482 char bind;
12483
12484 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
12485 {
12486 if (ARM_IS_THUMB (sym))
12487 {
12488 elf_symbol_type * elf_sym;
12489
12490 elf_sym = elf_symbol (symbol_get_bfdsym (sym));
12491 bind = ELF_ST_BIND (elf_sym);
12492
12493 /* If it's a .thumb_func, declare it as so,
12494 otherwise tag label as .code 16. */
12495 if (THUMB_IS_FUNC (sym))
12496 elf_sym->internal_elf_sym.st_info =
12497 ELF_ST_INFO (bind, STT_ARM_TFUNC);
12498 else
12499 elf_sym->internal_elf_sym.st_info =
12500 ELF_ST_INFO (bind, STT_ARM_16BIT);
12501 }
12502 }
12503#endif
12504}
12505
12506int
12507arm_data_in_code ()
12508{
12509 if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
12510 {
12511 *input_line_pointer = '/';
12512 input_line_pointer += 5;
12513 *input_line_pointer = 0;
12514 return 1;
12515 }
12516
12517 return 0;
12518}
12519
12520char *
12521arm_canonicalize_symbol_name (name)
12522 char * name;
12523{
12524 int len;
12525
12526 if (thumb_mode && (len = strlen (name)) > 5
12527 && streq (name + len - 5, "/data"))
12528 *(name + len - 5) = 0;
12529
12530 return name;
12531}
12532
bfc866a6 12533#if defined OBJ_COFF || defined OBJ_ELF
a161fe53 12534void
b99bd4ef
NC
12535arm_validate_fix (fixP)
12536 fixS * fixP;
12537{
12538 /* If the destination of the branch is a defined symbol which does not have
12539 the THUMB_FUNC attribute, then we must be calling a function which has
12540 the (interfacearm) attribute. We look for the Thumb entry point to that
12541 function and change the branch to refer to that function instead. */
12542 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
12543 && fixP->fx_addsy != NULL
12544 && S_IS_DEFINED (fixP->fx_addsy)
12545 && ! THUMB_IS_FUNC (fixP->fx_addsy))
12546 {
12547 fixP->fx_addsy = find_real_start (fixP->fx_addsy);
b99bd4ef 12548 }
b99bd4ef 12549}
bfc866a6 12550#endif
b99bd4ef 12551
114424c6
AM
12552int
12553arm_force_relocation (fixp)
12554 struct fix * fixp;
12555{
12556#if defined (OBJ_COFF) && defined (TE_PE)
12557 if (fixp->fx_r_type == BFD_RELOC_RVA)
12558 return 1;
12559#endif
12560#ifdef OBJ_ELF
ae6063d4 12561 if (fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
114424c6
AM
12562 || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
12563 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
12564 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
12565 return 1;
12566#endif
12567
12568 /* Resolve these relocations even if the symbol is extern or weak. */
12569 if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
47281638 12570 || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
114424c6
AM
12571 || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
12572 return 0;
12573
ae6063d4 12574 return generic_force_reloc (fixp);
114424c6
AM
12575}
12576
b99bd4ef
NC
12577#ifdef OBJ_COFF
12578/* This is a little hack to help the gas/arm/adrl.s test. It prevents
12579 local labels from being added to the output symbol table when they
12580 are used with the ADRL pseudo op. The ADRL relocation should always
12581 be resolved before the binbary is emitted, so it is safe to say that
12582 it is adjustable. */
12583
b34976b6 12584bfd_boolean
b99bd4ef
NC
12585arm_fix_adjustable (fixP)
12586 fixS * fixP;
12587{
12588 if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
12589 return 1;
12590 return 0;
12591}
12592#endif
114424c6 12593
b99bd4ef
NC
12594#ifdef OBJ_ELF
12595/* Relocations against Thumb function names must be left unadjusted,
12596 so that the linker can use this information to correctly set the
12597 bottom bit of their addresses. The MIPS version of this function
12598 also prevents relocations that are mips-16 specific, but I do not
12599 know why it does this.
12600
12601 FIXME:
12602 There is one other problem that ought to be addressed here, but
12603 which currently is not: Taking the address of a label (rather
12604 than a function) and then later jumping to that address. Such
12605 addresses also ought to have their bottom bit set (assuming that
12606 they reside in Thumb code), but at the moment they will not. */
12607
b34976b6 12608bfd_boolean
b99bd4ef
NC
12609arm_fix_adjustable (fixP)
12610 fixS * fixP;
12611{
12612 if (fixP->fx_addsy == NULL)
12613 return 1;
12614
b99bd4ef
NC
12615 if (THUMB_IS_FUNC (fixP->fx_addsy)
12616 && fixP->fx_subsy == NULL)
12617 return 0;
12618
12619 /* We need the symbol name for the VTABLE entries. */
12620 if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
12621 || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
12622 return 0;
12623
a161fe53
AM
12624 /* Don't allow symbols to be discarded on GOT related relocs. */
12625 if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
12626 || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
12627 || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF)
12628 return 0;
12629
b99bd4ef
NC
12630 return 1;
12631}
12632
12633const char *
12634elf32_arm_target_format ()
12635{
12636 if (target_big_endian)
12637 {
12638 if (target_oabi)
12639 return "elf32-bigarm-oabi";
12640 else
12641 return "elf32-bigarm";
12642 }
12643 else
12644 {
12645 if (target_oabi)
12646 return "elf32-littlearm-oabi";
12647 else
12648 return "elf32-littlearm";
12649 }
12650}
12651
12652void
12653armelf_frob_symbol (symp, puntp)
12654 symbolS * symp;
12655 int * puntp;
12656{
12657 elf_frob_symbol (symp, puntp);
12658}
12659
b99bd4ef
NC
12660static bfd_reloc_code_real_type
12661arm_parse_reloc ()
12662{
12663 char id [16];
12664 char * ip;
12665 unsigned int i;
12666 static struct
12667 {
12668 char * str;
12669 int len;
12670 bfd_reloc_code_real_type reloc;
12671 }
12672 reloc_map[] =
12673 {
12674#define MAP(str,reloc) { str, sizeof (str) - 1, reloc }
12675 MAP ("(got)", BFD_RELOC_ARM_GOT32),
12676 MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
12677 /* ScottB: Jan 30, 1998 - Added support for parsing "var(PLT)"
12678 branch instructions generated by GCC for PLT relocs. */
12679 MAP ("(plt)", BFD_RELOC_ARM_PLT32),
12680 { NULL, 0, BFD_RELOC_UNUSED }
12681#undef MAP
12682 };
12683
12684 for (i = 0, ip = input_line_pointer;
3882b010 12685 i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip));
b99bd4ef 12686 i++, ip++)
3882b010 12687 id[i] = TOLOWER (*ip);
b99bd4ef
NC
12688
12689 for (i = 0; reloc_map[i].str; i++)
12690 if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
12691 break;
12692
12693 input_line_pointer += reloc_map[i].len;
12694
12695 return reloc_map[i].reloc;
12696}
12697
12698static void
12699s_arm_elf_cons (nbytes)
12700 int nbytes;
12701{
12702 expressionS exp;
12703
12704#ifdef md_flush_pending_output
12705 md_flush_pending_output ();
12706#endif
12707
12708 if (is_it_end_of_statement ())
12709 {
12710 demand_empty_rest_of_line ();
12711 return;
12712 }
12713
12714#ifdef md_cons_align
12715 md_cons_align (nbytes);
12716#endif
12717
12718 do
12719 {
12720 bfd_reloc_code_real_type reloc;
12721
12722 expression (& exp);
12723
12724 if (exp.X_op == O_symbol
12725 && * input_line_pointer == '('
12726 && (reloc = arm_parse_reloc ()) != BFD_RELOC_UNUSED)
12727 {
12728 reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
12729 int size = bfd_get_reloc_size (howto);
12730
12731 if (size > nbytes)
12732 as_bad ("%s relocations do not fit in %d bytes",
12733 howto->name, nbytes);
12734 else
12735 {
12736 register char *p = frag_more ((int) nbytes);
12737 int offset = nbytes - size;
12738
12739 fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
12740 &exp, 0, reloc);
12741 }
12742 }
12743 else
12744 emit_expr (&exp, (unsigned int) nbytes);
12745 }
12746 while (*input_line_pointer++ == ',');
12747
12748 /* Put terminator back into stream. */
12749 input_line_pointer --;
12750 demand_empty_rest_of_line ();
12751}
12752
12753#endif /* OBJ_ELF */
12754
12755/* This is called from HANDLE_ALIGN in write.c. Fill in the contents
12756 of an rs_align_code fragment. */
12757
12758void
12759arm_handle_align (fragP)
12760 fragS *fragP;
12761{
12762 static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
12763 static char const thumb_noop[2] = { 0xc0, 0x46 };
12764 static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
12765 static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
12766
12767 int bytes, fix, noop_size;
12768 char * p;
12769 const char * noop;
cc8a6dd0 12770
b99bd4ef
NC
12771 if (fragP->fr_type != rs_align_code)
12772 return;
12773
12774 bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
12775 p = fragP->fr_literal + fragP->fr_fix;
12776 fix = 0;
cc8a6dd0 12777
b99bd4ef
NC
12778 if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
12779 bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
cc8a6dd0 12780
b99bd4ef
NC
12781 if (fragP->tc_frag_data)
12782 {
12783 if (target_big_endian)
12784 noop = thumb_bigend_noop;
12785 else
12786 noop = thumb_noop;
12787 noop_size = sizeof (thumb_noop);
12788 }
12789 else
12790 {
12791 if (target_big_endian)
12792 noop = arm_bigend_noop;
12793 else
12794 noop = arm_noop;
12795 noop_size = sizeof (arm_noop);
12796 }
cc8a6dd0 12797
b99bd4ef
NC
12798 if (bytes & (noop_size - 1))
12799 {
12800 fix = bytes & (noop_size - 1);
12801 memset (p, 0, fix);
12802 p += fix;
12803 bytes -= fix;
12804 }
12805
12806 while (bytes >= noop_size)
12807 {
12808 memcpy (p, noop, noop_size);
12809 p += noop_size;
12810 bytes -= noop_size;
12811 fix += noop_size;
12812 }
cc8a6dd0 12813
b99bd4ef
NC
12814 fragP->fr_fix += fix;
12815 fragP->fr_var = noop_size;
12816}
12817
12818/* Called from md_do_align. Used to create an alignment
12819 frag in a code section. */
12820
12821void
12822arm_frag_align_code (n, max)
12823 int n;
12824 int max;
12825{
12826 char * p;
12827
12828 /* We assume that there will never be a requirment
12829 to support alignments greater than 32 bytes. */
12830 if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
12831 as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
cc8a6dd0 12832
b99bd4ef
NC
12833 p = frag_var (rs_align_code,
12834 MAX_MEM_FOR_RS_ALIGN_CODE,
12835 1,
12836 (relax_substateT) max,
12837 (symbolS *) NULL,
12838 (offsetT) n,
12839 (char *) NULL);
12840 *p = 0;
12841
12842}
12843
12844/* Perform target specific initialisation of a frag. */
12845
12846void
12847arm_init_frag (fragP)
12848 fragS *fragP;
12849{
12850 /* Record whether this frag is in an ARM or a THUMB area. */
12851 fragP->tc_frag_data = thumb_mode;
12852}