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