]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/config/tc-arm.c
Set the machine number as well as the architecture when converting from a
[thirdparty/binutils-gdb.git] / gas / config / tc-arm.c
CommitLineData
b99bd4ef 1/* tc-arm.c -- Assemble for the ARM
ae6063d4 2 Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
b99bd4ef
NC
3 Free Software Foundation, Inc.
4 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
5 Modified by David Taylor (dtaylor@armltd.co.uk)
22d9c8c5 6 Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
b99bd4ef
NC
7
8 This file is part of GAS, the GNU Assembler.
9
10 GAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 GAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GAS; see the file COPYING. If not, write to the Free
22 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 02111-1307, USA. */
24
b99bd4ef
NC
25#include <string.h>
26#define NO_RELOC 0
27#include "as.h"
3882b010 28#include "safe-ctype.h"
b99bd4ef
NC
29
30/* Need TARGET_CPU. */
31#include "config.h"
32#include "subsegs.h"
33#include "obstack.h"
34#include "symbols.h"
35#include "listing.h"
36
37#ifdef OBJ_ELF
38#include "elf/arm.h"
39#include "dwarf2dbg.h"
40#endif
41
03b1477f
RE
42/* XXX Set this to 1 after the next binutils release */
43#define WARN_DEPRECATED 0
44
b89dddec
RE
45/* The following bitmasks control CPU extensions: */
46#define ARM_EXT_V1 0x00000001 /* All processors (core set). */
47#define ARM_EXT_V2 0x00000002 /* Multiply instructions. */
48#define ARM_EXT_V2S 0x00000004 /* SWP instructions. */
49#define ARM_EXT_V3 0x00000008 /* MSR MRS. */
50#define ARM_EXT_V3M 0x00000010 /* Allow long multiplies. */
51#define ARM_EXT_V4 0x00000020 /* Allow half word loads. */
52#define ARM_EXT_V4T 0x00000040 /* Thumb v1. */
53#define ARM_EXT_V5 0x00000080 /* Allow CLZ, etc. */
54#define ARM_EXT_V5T 0x00000100 /* Thumb v2. */
55#define ARM_EXT_V5ExP 0x00000200 /* DSP core set. */
56#define ARM_EXT_V5E 0x00000400 /* DSP Double transfers. */
ea6ef066 57#define ARM_EXT_V5J 0x00000800 /* Jazelle extension. */
03b1477f
RE
58
59/* Co-processor space extensions. */
60#define ARM_CEXT_XSCALE 0x00800000 /* Allow MIA etc. */
61#define ARM_CEXT_MAVERICK 0x00400000 /* Use Cirrus/DSP coprocessor. */
5a6c6817 62#define ARM_CEXT_IWMMXT 0x00200000 /* Intel Wireless MMX technology coprocessor. */
b89dddec
RE
63
64/* Architectures are the sum of the base and extensions. The ARM ARM (rev E)
65 defines the following: ARMv3, ARMv3M, ARMv4xM, ARMv4, ARMv4TxM, ARMv4T,
66 ARMv5xM, ARMv5, ARMv5TxM, ARMv5T, ARMv5TExP, ARMv5TE. To these we add
67 three more to cover cores prior to ARM6. Finally, there are cores which
68 implement further extensions in the co-processor space. */
69#define ARM_ARCH_V1 ARM_EXT_V1
70#define ARM_ARCH_V2 (ARM_ARCH_V1 | ARM_EXT_V2)
71#define ARM_ARCH_V2S (ARM_ARCH_V2 | ARM_EXT_V2S)
72#define ARM_ARCH_V3 (ARM_ARCH_V2S | ARM_EXT_V3)
73#define ARM_ARCH_V3M (ARM_ARCH_V3 | ARM_EXT_V3M)
74#define ARM_ARCH_V4xM (ARM_ARCH_V3 | ARM_EXT_V4)
75#define ARM_ARCH_V4 (ARM_ARCH_V3M | ARM_EXT_V4)
76#define ARM_ARCH_V4TxM (ARM_ARCH_V4xM | ARM_EXT_V4T)
77#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_EXT_V4T)
78#define ARM_ARCH_V5xM (ARM_ARCH_V4xM | ARM_EXT_V5)
79#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5)
80#define ARM_ARCH_V5TxM (ARM_ARCH_V5xM | ARM_EXT_V4T | ARM_EXT_V5T)
81#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_EXT_V4T | ARM_EXT_V5T)
82#define ARM_ARCH_V5TExP (ARM_ARCH_V5T | ARM_EXT_V5ExP)
83#define ARM_ARCH_V5TE (ARM_ARCH_V5TExP | ARM_EXT_V5E)
ea6ef066 84#define ARM_ARCH_V5TEJ (ARM_ARCH_V5TE | ARM_EXT_V5J)
03b1477f 85
b89dddec 86/* Processors with specific extensions in the co-processor space. */
03b1477f 87#define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_CEXT_XSCALE)
5a6c6817 88#define ARM_ARCH_IWMMXT (ARM_ARCH_XSCALE | ARM_CEXT_IWMMXT)
b99bd4ef
NC
89
90/* Some useful combinations: */
03b1477f
RE
91#define ARM_ANY 0x0000ffff /* Any basic core. */
92#define ARM_ALL 0x00ffffff /* Any core + co-processor */
93#define CPROC_ANY 0x00ff0000 /* Any co-processor */
94#define FPU_ANY 0xff000000 /* Note this is ~ARM_ALL. */
95
b99bd4ef 96
bfae80f2
RE
97#define FPU_FPA_EXT_V1 0x80000000 /* Base FPA instruction set. */
98#define FPU_FPA_EXT_V2 0x40000000 /* LFM/SFM. */
99#define FPU_VFP_EXT_NONE 0x20000000 /* Use VFP word-ordering. */
100#define FPU_VFP_EXT_V1xD 0x10000000 /* Base VFP instruction set. */
101#define FPU_VFP_EXT_V1 0x08000000 /* Double-precision insns. */
102#define FPU_VFP_EXT_V2 0x04000000 /* ARM10E VFPr1. */
103#define FPU_NONE 0
b99bd4ef 104
b89dddec
RE
105#define FPU_ARCH_FPE FPU_FPA_EXT_V1
106#define FPU_ARCH_FPA (FPU_ARCH_FPE | FPU_FPA_EXT_V2)
107
bfae80f2
RE
108#define FPU_ARCH_VFP FPU_VFP_EXT_NONE
109#define FPU_ARCH_VFP_V1xD (FPU_VFP_EXT_V1xD | FPU_VFP_EXT_NONE)
110#define FPU_ARCH_VFP_V1 (FPU_ARCH_VFP_V1xD | FPU_VFP_EXT_V1)
111#define FPU_ARCH_VFP_V2 (FPU_ARCH_VFP_V1 | FPU_VFP_EXT_V2)
112
b89dddec
RE
113/* Types of processor to assemble for. */
114#define ARM_1 ARM_ARCH_V1
115#define ARM_2 ARM_ARCH_V2
116#define ARM_3 ARM_ARCH_V2S
117#define ARM_250 ARM_ARCH_V2S
118#define ARM_6 ARM_ARCH_V3
119#define ARM_7 ARM_ARCH_V3
120#define ARM_8 ARM_ARCH_V4
121#define ARM_9 ARM_ARCH_V4T
122#define ARM_STRONG ARM_ARCH_V4
123#define ARM_CPU_MASK 0x0000000f /* XXX? */
b99bd4ef
NC
124
125#ifndef CPU_DEFAULT
126#if defined __XSCALE__
b89dddec 127#define CPU_DEFAULT (ARM_ARCH_XSCALE)
b99bd4ef
NC
128#else
129#if defined __thumb__
b89dddec 130#define CPU_DEFAULT (ARM_ARCH_V5T)
b99bd4ef 131#else
03b1477f 132#define CPU_DEFAULT ARM_ANY
b99bd4ef
NC
133#endif
134#endif
135#endif
136
39c2da32
RE
137#ifdef TE_LINUX
138#define FPU_DEFAULT FPU_ARCH_FPA
139#endif
140
141#ifdef TE_NetBSD
142#ifdef OBJ_ELF
143#define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, but VFP order. */
144#else
145/* Legacy a.out format. */
146#define FPU_DEFAULT FPU_ARCH_FPA /* Soft-float, but FPA order. */
147#endif
148#endif
149
bfae80f2 150/* For backwards compatibility we default to the FPA. */
b99bd4ef 151#ifndef FPU_DEFAULT
b89dddec 152#define FPU_DEFAULT FPU_ARCH_FPA
b99bd4ef
NC
153#endif
154
155#define streq(a, b) (strcmp (a, b) == 0)
156#define skip_whitespace(str) while (*(str) == ' ') ++(str)
157
03b1477f 158static unsigned long cpu_variant;
b99bd4ef
NC
159static int target_oabi = 0;
160
b99bd4ef 161/* Flags stored in private area of BFD structure. */
b34976b6
AM
162static int uses_apcs_26 = FALSE;
163static int atpcs = FALSE;
164static int support_interwork = FALSE;
165static int uses_apcs_float = FALSE;
166static int pic_code = FALSE;
03b1477f
RE
167
168/* Variables that we set while parsing command-line options. Once all
169 options have been read we re-process these values to set the real
170 assembly flags. */
171static int legacy_cpu = -1;
172static int legacy_fpu = -1;
173
174static int mcpu_cpu_opt = -1;
175static int mcpu_fpu_opt = -1;
176static int march_cpu_opt = -1;
177static int march_fpu_opt = -1;
178static int mfpu_opt = -1;
b99bd4ef
NC
179
180/* This array holds the chars that always start a comment. If the
181 pre-processor is disabled, these aren't very useful. */
f57c81f6 182const char comment_chars[] = "@";
b99bd4ef
NC
183
184/* This array holds the chars that only start a comment at the beginning of
185 a line. If the line seems to have the form '# 123 filename'
186 .line and .file directives will appear in the pre-processed output. */
187/* Note that input_file.c hand checks for '#' at the beginning of the
188 first line of the input file. This is because the compiler outputs
189 #NO_APP at the beginning of its output. */
190/* Also note that comments like this one will always work. */
05d2d07e 191const char line_comment_chars[] = "#";
b99bd4ef 192
da89cce1 193const char line_separator_chars[] = ";";
b99bd4ef
NC
194
195/* Chars that can be used to separate mant
196 from exp in floating point numbers. */
05d2d07e 197const char EXP_CHARS[] = "eE";
b99bd4ef
NC
198
199/* Chars that mean this number is a floating point constant. */
200/* As in 0f12.456 */
201/* or 0d1.2345e12 */
202
05d2d07e 203const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
b99bd4ef
NC
204
205/* Prefix characters that indicate the start of an immediate
206 value. */
207#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
208
209#ifdef OBJ_ELF
210/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
211symbolS * GOT_symbol;
212#endif
213
214/* Size of relocation record. */
05d2d07e 215const int md_reloc_size = 8;
b99bd4ef
NC
216
217/* 0: assemble for ARM,
218 1: assemble for Thumb,
219 2: assemble for Thumb even though target CPU does not support thumb
220 instructions. */
221static int thumb_mode = 0;
222
223typedef struct arm_fix
224{
225 int thumb_mode;
226} arm_fix_data;
227
228struct arm_it
229{
05d2d07e 230 const char * error;
b99bd4ef 231 unsigned long instruction;
b99bd4ef
NC
232 int size;
233 struct
234 {
235 bfd_reloc_code_real_type type;
236 expressionS exp;
237 int pc_rel;
238 } reloc;
239};
240
241struct arm_it inst;
242
243enum asm_shift_index
244{
245 SHIFT_LSL = 0,
246 SHIFT_LSR,
247 SHIFT_ASR,
248 SHIFT_ROR,
249 SHIFT_RRX
250};
251
252struct asm_shift_properties
253{
254 enum asm_shift_index index;
255 unsigned long bit_field;
256 unsigned int allows_0 : 1;
257 unsigned int allows_32 : 1;
258};
259
260static const struct asm_shift_properties shift_properties [] =
261{
262 { SHIFT_LSL, 0, 1, 0},
263 { SHIFT_LSR, 0x20, 0, 1},
264 { SHIFT_ASR, 0x40, 0, 1},
265 { SHIFT_ROR, 0x60, 0, 0},
266 { SHIFT_RRX, 0x60, 0, 0}
267};
268
269struct asm_shift_name
270{
271 const char * name;
272 const struct asm_shift_properties * properties;
273};
274
275static const struct asm_shift_name shift_names [] =
276{
277 { "asl", shift_properties + SHIFT_LSL },
278 { "lsl", shift_properties + SHIFT_LSL },
279 { "lsr", shift_properties + SHIFT_LSR },
280 { "asr", shift_properties + SHIFT_ASR },
281 { "ror", shift_properties + SHIFT_ROR },
282 { "rrx", shift_properties + SHIFT_RRX },
283 { "ASL", shift_properties + SHIFT_LSL },
284 { "LSL", shift_properties + SHIFT_LSL },
285 { "LSR", shift_properties + SHIFT_LSR },
286 { "ASR", shift_properties + SHIFT_ASR },
287 { "ROR", shift_properties + SHIFT_ROR },
288 { "RRX", shift_properties + SHIFT_RRX }
289};
290
291#define NO_SHIFT_RESTRICT 1
292#define SHIFT_RESTRICT 0
293
294#define NUM_FLOAT_VALS 8
295
05d2d07e 296const char * fp_const[] =
b99bd4ef
NC
297{
298 "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
299};
300
301/* Number of littlenums required to hold an extended precision number. */
302#define MAX_LITTLENUMS 6
303
304LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
305
306#define FAIL (-1)
307#define SUCCESS (0)
308
bfae80f2
RE
309/* Whether a Co-processor load/store operation accepts write-back forms. */
310#define CP_WB_OK 1
311#define CP_NO_WB 0
312
b99bd4ef
NC
313#define SUFF_S 1
314#define SUFF_D 2
315#define SUFF_E 3
316#define SUFF_P 4
317
318#define CP_T_X 0x00008000
319#define CP_T_Y 0x00400000
320#define CP_T_Pre 0x01000000
321#define CP_T_UD 0x00800000
322#define CP_T_WB 0x00200000
323
324#define CONDS_BIT 0x00100000
325#define LOAD_BIT 0x00100000
b99bd4ef
NC
326
327#define DOUBLE_LOAD_FLAG 0x00000001
328
329struct asm_cond
330{
05d2d07e 331 const char * template;
b99bd4ef
NC
332 unsigned long value;
333};
334
b99bd4ef 335#define COND_ALWAYS 0xe0000000
90e4755a 336#define COND_MASK 0xf0000000
b99bd4ef 337
05d2d07e 338static const struct asm_cond conds[] =
b99bd4ef
NC
339{
340 {"eq", 0x00000000},
341 {"ne", 0x10000000},
342 {"cs", 0x20000000}, {"hs", 0x20000000},
343 {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000},
344 {"mi", 0x40000000},
345 {"pl", 0x50000000},
346 {"vs", 0x60000000},
347 {"vc", 0x70000000},
348 {"hi", 0x80000000},
349 {"ls", 0x90000000},
350 {"ge", 0xa0000000},
351 {"lt", 0xb0000000},
352 {"gt", 0xc0000000},
353 {"le", 0xd0000000},
354 {"al", 0xe0000000},
355 {"nv", 0xf0000000}
356};
357
b99bd4ef
NC
358struct asm_psr
359{
b34976b6
AM
360 const char *template;
361 bfd_boolean cpsr;
b99bd4ef
NC
362 unsigned long field;
363};
364
365/* The bit that distnguishes CPSR and SPSR. */
366#define SPSR_BIT (1 << 22)
367
368/* How many bits to shift the PSR_xxx bits up by. */
369#define PSR_SHIFT 16
370
371#define PSR_c (1 << 0)
372#define PSR_x (1 << 1)
373#define PSR_s (1 << 2)
374#define PSR_f (1 << 3)
375
05d2d07e 376static const struct asm_psr psrs[] =
b99bd4ef 377{
b34976b6
AM
378 {"CPSR", TRUE, PSR_c | PSR_f},
379 {"CPSR_all", TRUE, PSR_c | PSR_f},
380 {"SPSR", FALSE, PSR_c | PSR_f},
381 {"SPSR_all", FALSE, PSR_c | PSR_f},
382 {"CPSR_flg", TRUE, PSR_f},
383 {"CPSR_f", TRUE, PSR_f},
384 {"SPSR_flg", FALSE, PSR_f},
385 {"SPSR_f", FALSE, PSR_f},
386 {"CPSR_c", TRUE, PSR_c},
387 {"CPSR_ctl", TRUE, PSR_c},
388 {"SPSR_c", FALSE, PSR_c},
389 {"SPSR_ctl", FALSE, PSR_c},
390 {"CPSR_x", TRUE, PSR_x},
391 {"CPSR_s", TRUE, PSR_s},
392 {"SPSR_x", FALSE, PSR_x},
393 {"SPSR_s", FALSE, PSR_s},
b99bd4ef 394 /* Combinations of flags. */
b34976b6
AM
395 {"CPSR_fs", TRUE, PSR_f | PSR_s},
396 {"CPSR_fx", TRUE, PSR_f | PSR_x},
397 {"CPSR_fc", TRUE, PSR_f | PSR_c},
398 {"CPSR_sf", TRUE, PSR_s | PSR_f},
399 {"CPSR_sx", TRUE, PSR_s | PSR_x},
400 {"CPSR_sc", TRUE, PSR_s | PSR_c},
401 {"CPSR_xf", TRUE, PSR_x | PSR_f},
402 {"CPSR_xs", TRUE, PSR_x | PSR_s},
403 {"CPSR_xc", TRUE, PSR_x | PSR_c},
404 {"CPSR_cf", TRUE, PSR_c | PSR_f},
405 {"CPSR_cs", TRUE, PSR_c | PSR_s},
406 {"CPSR_cx", TRUE, PSR_c | PSR_x},
407 {"CPSR_fsx", TRUE, PSR_f | PSR_s | PSR_x},
408 {"CPSR_fsc", TRUE, PSR_f | PSR_s | PSR_c},
409 {"CPSR_fxs", TRUE, PSR_f | PSR_x | PSR_s},
410 {"CPSR_fxc", TRUE, PSR_f | PSR_x | PSR_c},
411 {"CPSR_fcs", TRUE, PSR_f | PSR_c | PSR_s},
412 {"CPSR_fcx", TRUE, PSR_f | PSR_c | PSR_x},
413 {"CPSR_sfx", TRUE, PSR_s | PSR_f | PSR_x},
414 {"CPSR_sfc", TRUE, PSR_s | PSR_f | PSR_c},
415 {"CPSR_sxf", TRUE, PSR_s | PSR_x | PSR_f},
416 {"CPSR_sxc", TRUE, PSR_s | PSR_x | PSR_c},
417 {"CPSR_scf", TRUE, PSR_s | PSR_c | PSR_f},
418 {"CPSR_scx", TRUE, PSR_s | PSR_c | PSR_x},
419 {"CPSR_xfs", TRUE, PSR_x | PSR_f | PSR_s},
420 {"CPSR_xfc", TRUE, PSR_x | PSR_f | PSR_c},
421 {"CPSR_xsf", TRUE, PSR_x | PSR_s | PSR_f},
422 {"CPSR_xsc", TRUE, PSR_x | PSR_s | PSR_c},
423 {"CPSR_xcf", TRUE, PSR_x | PSR_c | PSR_f},
424 {"CPSR_xcs", TRUE, PSR_x | PSR_c | PSR_s},
425 {"CPSR_cfs", TRUE, PSR_c | PSR_f | PSR_s},
426 {"CPSR_cfx", TRUE, PSR_c | PSR_f | PSR_x},
427 {"CPSR_csf", TRUE, PSR_c | PSR_s | PSR_f},
428 {"CPSR_csx", TRUE, PSR_c | PSR_s | PSR_x},
429 {"CPSR_cxf", TRUE, PSR_c | PSR_x | PSR_f},
430 {"CPSR_cxs", TRUE, PSR_c | PSR_x | PSR_s},
431 {"CPSR_fsxc", TRUE, PSR_f | PSR_s | PSR_x | PSR_c},
432 {"CPSR_fscx", TRUE, PSR_f | PSR_s | PSR_c | PSR_x},
433 {"CPSR_fxsc", TRUE, PSR_f | PSR_x | PSR_s | PSR_c},
434 {"CPSR_fxcs", TRUE, PSR_f | PSR_x | PSR_c | PSR_s},
435 {"CPSR_fcsx", TRUE, PSR_f | PSR_c | PSR_s | PSR_x},
436 {"CPSR_fcxs", TRUE, PSR_f | PSR_c | PSR_x | PSR_s},
437 {"CPSR_sfxc", TRUE, PSR_s | PSR_f | PSR_x | PSR_c},
438 {"CPSR_sfcx", TRUE, PSR_s | PSR_f | PSR_c | PSR_x},
439 {"CPSR_sxfc", TRUE, PSR_s | PSR_x | PSR_f | PSR_c},
440 {"CPSR_sxcf", TRUE, PSR_s | PSR_x | PSR_c | PSR_f},
441 {"CPSR_scfx", TRUE, PSR_s | PSR_c | PSR_f | PSR_x},
442 {"CPSR_scxf", TRUE, PSR_s | PSR_c | PSR_x | PSR_f},
443 {"CPSR_xfsc", TRUE, PSR_x | PSR_f | PSR_s | PSR_c},
444 {"CPSR_xfcs", TRUE, PSR_x | PSR_f | PSR_c | PSR_s},
445 {"CPSR_xsfc", TRUE, PSR_x | PSR_s | PSR_f | PSR_c},
446 {"CPSR_xscf", TRUE, PSR_x | PSR_s | PSR_c | PSR_f},
447 {"CPSR_xcfs", TRUE, PSR_x | PSR_c | PSR_f | PSR_s},
448 {"CPSR_xcsf", TRUE, PSR_x | PSR_c | PSR_s | PSR_f},
449 {"CPSR_cfsx", TRUE, PSR_c | PSR_f | PSR_s | PSR_x},
450 {"CPSR_cfxs", TRUE, PSR_c | PSR_f | PSR_x | PSR_s},
451 {"CPSR_csfx", TRUE, PSR_c | PSR_s | PSR_f | PSR_x},
452 {"CPSR_csxf", TRUE, PSR_c | PSR_s | PSR_x | PSR_f},
453 {"CPSR_cxfs", TRUE, PSR_c | PSR_x | PSR_f | PSR_s},
454 {"CPSR_cxsf", TRUE, PSR_c | PSR_x | PSR_s | PSR_f},
455 {"SPSR_fs", FALSE, PSR_f | PSR_s},
456 {"SPSR_fx", FALSE, PSR_f | PSR_x},
457 {"SPSR_fc", FALSE, PSR_f | PSR_c},
458 {"SPSR_sf", FALSE, PSR_s | PSR_f},
459 {"SPSR_sx", FALSE, PSR_s | PSR_x},
460 {"SPSR_sc", FALSE, PSR_s | PSR_c},
461 {"SPSR_xf", FALSE, PSR_x | PSR_f},
462 {"SPSR_xs", FALSE, PSR_x | PSR_s},
463 {"SPSR_xc", FALSE, PSR_x | PSR_c},
464 {"SPSR_cf", FALSE, PSR_c | PSR_f},
465 {"SPSR_cs", FALSE, PSR_c | PSR_s},
466 {"SPSR_cx", FALSE, PSR_c | PSR_x},
467 {"SPSR_fsx", FALSE, PSR_f | PSR_s | PSR_x},
468 {"SPSR_fsc", FALSE, PSR_f | PSR_s | PSR_c},
469 {"SPSR_fxs", FALSE, PSR_f | PSR_x | PSR_s},
470 {"SPSR_fxc", FALSE, PSR_f | PSR_x | PSR_c},
471 {"SPSR_fcs", FALSE, PSR_f | PSR_c | PSR_s},
472 {"SPSR_fcx", FALSE, PSR_f | PSR_c | PSR_x},
473 {"SPSR_sfx", FALSE, PSR_s | PSR_f | PSR_x},
474 {"SPSR_sfc", FALSE, PSR_s | PSR_f | PSR_c},
475 {"SPSR_sxf", FALSE, PSR_s | PSR_x | PSR_f},
476 {"SPSR_sxc", FALSE, PSR_s | PSR_x | PSR_c},
477 {"SPSR_scf", FALSE, PSR_s | PSR_c | PSR_f},
478 {"SPSR_scx", FALSE, PSR_s | PSR_c | PSR_x},
479 {"SPSR_xfs", FALSE, PSR_x | PSR_f | PSR_s},
480 {"SPSR_xfc", FALSE, PSR_x | PSR_f | PSR_c},
481 {"SPSR_xsf", FALSE, PSR_x | PSR_s | PSR_f},
482 {"SPSR_xsc", FALSE, PSR_x | PSR_s | PSR_c},
483 {"SPSR_xcf", FALSE, PSR_x | PSR_c | PSR_f},
484 {"SPSR_xcs", FALSE, PSR_x | PSR_c | PSR_s},
485 {"SPSR_cfs", FALSE, PSR_c | PSR_f | PSR_s},
486 {"SPSR_cfx", FALSE, PSR_c | PSR_f | PSR_x},
487 {"SPSR_csf", FALSE, PSR_c | PSR_s | PSR_f},
488 {"SPSR_csx", FALSE, PSR_c | PSR_s | PSR_x},
489 {"SPSR_cxf", FALSE, PSR_c | PSR_x | PSR_f},
490 {"SPSR_cxs", FALSE, PSR_c | PSR_x | PSR_s},
491 {"SPSR_fsxc", FALSE, PSR_f | PSR_s | PSR_x | PSR_c},
492 {"SPSR_fscx", FALSE, PSR_f | PSR_s | PSR_c | PSR_x},
493 {"SPSR_fxsc", FALSE, PSR_f | PSR_x | PSR_s | PSR_c},
494 {"SPSR_fxcs", FALSE, PSR_f | PSR_x | PSR_c | PSR_s},
495 {"SPSR_fcsx", FALSE, PSR_f | PSR_c | PSR_s | PSR_x},
496 {"SPSR_fcxs", FALSE, PSR_f | PSR_c | PSR_x | PSR_s},
497 {"SPSR_sfxc", FALSE, PSR_s | PSR_f | PSR_x | PSR_c},
498 {"SPSR_sfcx", FALSE, PSR_s | PSR_f | PSR_c | PSR_x},
499 {"SPSR_sxfc", FALSE, PSR_s | PSR_x | PSR_f | PSR_c},
500 {"SPSR_sxcf", FALSE, PSR_s | PSR_x | PSR_c | PSR_f},
501 {"SPSR_scfx", FALSE, PSR_s | PSR_c | PSR_f | PSR_x},
502 {"SPSR_scxf", FALSE, PSR_s | PSR_c | PSR_x | PSR_f},
503 {"SPSR_xfsc", FALSE, PSR_x | PSR_f | PSR_s | PSR_c},
504 {"SPSR_xfcs", FALSE, PSR_x | PSR_f | PSR_c | PSR_s},
505 {"SPSR_xsfc", FALSE, PSR_x | PSR_s | PSR_f | PSR_c},
506 {"SPSR_xscf", FALSE, PSR_x | PSR_s | PSR_c | PSR_f},
507 {"SPSR_xcfs", FALSE, PSR_x | PSR_c | PSR_f | PSR_s},
508 {"SPSR_xcsf", FALSE, PSR_x | PSR_c | PSR_s | PSR_f},
509 {"SPSR_cfsx", FALSE, PSR_c | PSR_f | PSR_s | PSR_x},
510 {"SPSR_cfxs", FALSE, PSR_c | PSR_f | PSR_x | PSR_s},
511 {"SPSR_csfx", FALSE, PSR_c | PSR_s | PSR_f | PSR_x},
512 {"SPSR_csxf", FALSE, PSR_c | PSR_s | PSR_x | PSR_f},
513 {"SPSR_cxfs", FALSE, PSR_c | PSR_x | PSR_f | PSR_s},
514 {"SPSR_cxsf", FALSE, PSR_c | PSR_x | PSR_s | PSR_f},
b99bd4ef
NC
515};
516
e16bb312
NC
517enum wreg_type
518 {
519 IWMMXT_REG_WR = 0,
520 IWMMXT_REG_WC = 1,
521 IWMMXT_REG_WR_OR_WC = 2,
522 IWMMXT_REG_WCG
523 };
524
525enum iwmmxt_insn_type
526{
527 check_rd,
528 check_wr,
529 check_wrwr,
530 check_wrwrwr,
531 check_wrwrwcg,
532 check_tbcst,
533 check_tmovmsk,
534 check_tmia,
535 check_tmcrr,
536 check_tmrrc,
537 check_tmcr,
538 check_tmrc,
539 check_tinsr,
540 check_textrc,
541 check_waligni,
542 check_textrm,
543 check_wshufh
544};
545
bfae80f2
RE
546enum vfp_dp_reg_pos
547{
548 VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
549};
550
551enum vfp_sp_reg_pos
552{
553 VFP_REG_Sd, VFP_REG_Sm, VFP_REG_Sn
554};
555
556enum vfp_ldstm_type
557{
558 VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX
559};
560
561/* VFP system registers. */
562struct vfp_reg
563{
564 const char *name;
565 unsigned long regno;
566};
567
cc8a6dd0 568static const struct vfp_reg vfp_regs[] =
bfae80f2
RE
569{
570 {"fpsid", 0x00000000},
571 {"FPSID", 0x00000000},
572 {"fpscr", 0x00010000},
573 {"FPSCR", 0x00010000},
574 {"fpexc", 0x00080000},
575 {"FPEXC", 0x00080000}
576};
577
6c43fab6
RE
578/* Structure for a hash table entry for a register. */
579struct reg_entry
580{
581 const char * name;
582 int number;
583};
584
e28cd48c 585/* Some well known registers that we refer to directly elsewhere. */
6c43fab6
RE
586#define REG_SP 13
587#define REG_LR 14
588#define REG_PC 15
589
e16bb312
NC
590#define wr_register(reg) ((reg ^ WR_PREFIX) >= 0 && (reg ^ WR_PREFIX) <= 15)
591#define wc_register(reg) ((reg ^ WC_PREFIX) >= 0 && (reg ^ WC_PREFIX) <= 15)
592#define wcg_register(reg) ((reg ^ WC_PREFIX) >= 8 && (reg ^ WC_PREFIX) <= 11)
593
6c43fab6
RE
594/* These are the standard names. Users can add aliases with .req. */
595/* Integer Register Numbers. */
596static const struct reg_entry rn_table[] =
597{
598 {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
599 {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
600 {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
601 {"r12", 12}, {"r13", REG_SP}, {"r14", REG_LR}, {"r15", REG_PC},
602 /* ATPCS Synonyms. */
603 {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3},
604 {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7},
605 {"v5", 8}, {"v6", 9}, {"v7", 10}, {"v8", 11},
606 /* Well-known aliases. */
607 {"wr", 7},
608 {"sb", 9}, {"sl", 10}, {"fp", 11},
609 {"ip", 12}, {"sp", REG_SP}, {"lr", REG_LR}, {"pc", REG_PC},
610 {NULL, 0}
611};
612
e16bb312
NC
613#define WR_PREFIX 0x200
614#define WC_PREFIX 0x400
615
616static const struct reg_entry iwmmxt_table[] =
617{
5a6c6817 618 /* Intel Wireless MMX technology register names. */
e16bb312
NC
619 { "wr0", 0x0 | WR_PREFIX}, {"wr1", 0x1 | WR_PREFIX},
620 { "wr2", 0x2 | WR_PREFIX}, {"wr3", 0x3 | WR_PREFIX},
621 { "wr4", 0x4 | WR_PREFIX}, {"wr5", 0x5 | WR_PREFIX},
622 { "wr6", 0x6 | WR_PREFIX}, {"wr7", 0x7 | WR_PREFIX},
623 { "wr8", 0x8 | WR_PREFIX}, {"wr9", 0x9 | WR_PREFIX},
624 { "wr10", 0xa | WR_PREFIX}, {"wr11", 0xb | WR_PREFIX},
625 { "wr12", 0xc | WR_PREFIX}, {"wr13", 0xd | WR_PREFIX},
626 { "wr14", 0xe | WR_PREFIX}, {"wr15", 0xf | WR_PREFIX},
627 { "wcid", 0x0 | WC_PREFIX}, {"wcon", 0x1 | WC_PREFIX},
628 {"wcssf", 0x2 | WC_PREFIX}, {"wcasf", 0x3 | WC_PREFIX},
629 {"wcgr0", 0x8 | WC_PREFIX}, {"wcgr1", 0x9 | WC_PREFIX},
630 {"wcgr2", 0xa | WC_PREFIX}, {"wcgr3", 0xb | WC_PREFIX},
631
632 { "wR0", 0x0 | WR_PREFIX}, {"wR1", 0x1 | WR_PREFIX},
633 { "wR2", 0x2 | WR_PREFIX}, {"wR3", 0x3 | WR_PREFIX},
634 { "wR4", 0x4 | WR_PREFIX}, {"wR5", 0x5 | WR_PREFIX},
635 { "wR6", 0x6 | WR_PREFIX}, {"wR7", 0x7 | WR_PREFIX},
636 { "wR8", 0x8 | WR_PREFIX}, {"wR9", 0x9 | WR_PREFIX},
637 { "wR10", 0xa | WR_PREFIX}, {"wR11", 0xb | WR_PREFIX},
638 { "wR12", 0xc | WR_PREFIX}, {"wR13", 0xd | WR_PREFIX},
639 { "wR14", 0xe | WR_PREFIX}, {"wR15", 0xf | WR_PREFIX},
640 { "wCID", 0x0 | WC_PREFIX}, {"wCon", 0x1 | WC_PREFIX},
641 {"wCSSF", 0x2 | WC_PREFIX}, {"wCASF", 0x3 | WC_PREFIX},
642 {"wCGR0", 0x8 | WC_PREFIX}, {"wCGR1", 0x9 | WC_PREFIX},
643 {"wCGR2", 0xa | WC_PREFIX}, {"wCGR3", 0xb | WC_PREFIX},
644 {NULL, 0}
645};
646
6c43fab6
RE
647/* Co-processor Numbers. */
648static const struct reg_entry cp_table[] =
649{
650 {"p0", 0}, {"p1", 1}, {"p2", 2}, {"p3", 3},
651 {"p4", 4}, {"p5", 5}, {"p6", 6}, {"p7", 7},
652 {"p8", 8}, {"p9", 9}, {"p10", 10}, {"p11", 11},
653 {"p12", 12}, {"p13", 13}, {"p14", 14}, {"p15", 15},
654 {NULL, 0}
655};
656
657/* Co-processor Register Numbers. */
658static const struct reg_entry cn_table[] =
659{
660 {"c0", 0}, {"c1", 1}, {"c2", 2}, {"c3", 3},
661 {"c4", 4}, {"c5", 5}, {"c6", 6}, {"c7", 7},
662 {"c8", 8}, {"c9", 9}, {"c10", 10}, {"c11", 11},
663 {"c12", 12}, {"c13", 13}, {"c14", 14}, {"c15", 15},
664 /* Not really valid, but kept for back-wards compatibility. */
665 {"cr0", 0}, {"cr1", 1}, {"cr2", 2}, {"cr3", 3},
666 {"cr4", 4}, {"cr5", 5}, {"cr6", 6}, {"cr7", 7},
667 {"cr8", 8}, {"cr9", 9}, {"cr10", 10}, {"cr11", 11},
668 {"cr12", 12}, {"cr13", 13}, {"cr14", 14}, {"cr15", 15},
669 {NULL, 0}
670};
671
672/* FPA Registers. */
673static const struct reg_entry fn_table[] =
674{
675 {"f0", 0}, {"f1", 1}, {"f2", 2}, {"f3", 3},
676 {"f4", 4}, {"f5", 5}, {"f6", 6}, {"f7", 7},
677 {NULL, 0}
678};
679
bfae80f2
RE
680/* VFP SP Registers. */
681static const struct reg_entry sn_table[] =
682{
683 {"s0", 0}, {"s1", 1}, {"s2", 2}, {"s3", 3},
684 {"s4", 4}, {"s5", 5}, {"s6", 6}, {"s7", 7},
685 {"s8", 8}, {"s9", 9}, {"s10", 10}, {"s11", 11},
686 {"s12", 12}, {"s13", 13}, {"s14", 14}, {"s15", 15},
687 {"s16", 16}, {"s17", 17}, {"s18", 18}, {"s19", 19},
688 {"s20", 20}, {"s21", 21}, {"s22", 22}, {"s23", 23},
689 {"s24", 24}, {"s25", 25}, {"s26", 26}, {"s27", 27},
690 {"s28", 28}, {"s29", 29}, {"s30", 30}, {"s31", 31},
691 {NULL, 0}
692};
693
694/* VFP DP Registers. */
695static const struct reg_entry dn_table[] =
696{
697 {"d0", 0}, {"d1", 1}, {"d2", 2}, {"d3", 3},
698 {"d4", 4}, {"d5", 5}, {"d6", 6}, {"d7", 7},
699 {"d8", 8}, {"d9", 9}, {"d10", 10}, {"d11", 11},
700 {"d12", 12}, {"d13", 13}, {"d14", 14}, {"d15", 15},
701 {NULL, 0}
702};
703
63e63b07 704/* Maverick DSP coprocessor registers. */
6c43fab6
RE
705static const struct reg_entry mav_mvf_table[] =
706{
707 {"mvf0", 0}, {"mvf1", 1}, {"mvf2", 2}, {"mvf3", 3},
708 {"mvf4", 4}, {"mvf5", 5}, {"mvf6", 6}, {"mvf7", 7},
709 {"mvf8", 8}, {"mvf9", 9}, {"mvf10", 10}, {"mvf11", 11},
710 {"mvf12", 12}, {"mvf13", 13}, {"mvf14", 14}, {"mvf15", 15},
711 {NULL, 0}
712};
713
714static const struct reg_entry mav_mvd_table[] =
715{
716 {"mvd0", 0}, {"mvd1", 1}, {"mvd2", 2}, {"mvd3", 3},
717 {"mvd4", 4}, {"mvd5", 5}, {"mvd6", 6}, {"mvd7", 7},
718 {"mvd8", 8}, {"mvd9", 9}, {"mvd10", 10}, {"mvd11", 11},
719 {"mvd12", 12}, {"mvd13", 13}, {"mvd14", 14}, {"mvd15", 15},
720 {NULL, 0}
721};
722
723static const struct reg_entry mav_mvfx_table[] =
724{
725 {"mvfx0", 0}, {"mvfx1", 1}, {"mvfx2", 2}, {"mvfx3", 3},
726 {"mvfx4", 4}, {"mvfx5", 5}, {"mvfx6", 6}, {"mvfx7", 7},
727 {"mvfx8", 8}, {"mvfx9", 9}, {"mvfx10", 10}, {"mvfx11", 11},
728 {"mvfx12", 12}, {"mvfx13", 13}, {"mvfx14", 14}, {"mvfx15", 15},
729 {NULL, 0}
730};
731
732static const struct reg_entry mav_mvdx_table[] =
733{
734 {"mvdx0", 0}, {"mvdx1", 1}, {"mvdx2", 2}, {"mvdx3", 3},
735 {"mvdx4", 4}, {"mvdx5", 5}, {"mvdx6", 6}, {"mvdx7", 7},
736 {"mvdx8", 8}, {"mvdx9", 9}, {"mvdx10", 10}, {"mvdx11", 11},
737 {"mvdx12", 12}, {"mvdx13", 13}, {"mvdx14", 14}, {"mvdx15", 15},
738 {NULL, 0}
739};
740
741static const struct reg_entry mav_mvax_table[] =
742{
743 {"mvax0", 0}, {"mvax1", 1}, {"mvax2", 2}, {"mvax3", 3},
744 {NULL, 0}
745};
746
747static const struct reg_entry mav_dspsc_table[] =
748{
749 {"dspsc", 0},
750 {NULL, 0}
751};
752
753struct reg_map
754{
755 const struct reg_entry *names;
756 int max_regno;
757 struct hash_control *htab;
758 const char *expected;
759};
760
761struct reg_map all_reg_maps[] =
762{
763 {rn_table, 15, NULL, N_("ARM register expected")},
f03698e6
RE
764 {cp_table, 15, NULL, N_("bad or missing co-processor number")},
765 {cn_table, 15, NULL, N_("co-processor register expected")},
6c43fab6 766 {fn_table, 7, NULL, N_("FPA register expected")},
bfae80f2
RE
767 {sn_table, 31, NULL, N_("VFP single precision register expected")},
768 {dn_table, 15, NULL, N_("VFP double precision register expected")},
6c43fab6
RE
769 {mav_mvf_table, 15, NULL, N_("Maverick MVF register expected")},
770 {mav_mvd_table, 15, NULL, N_("Maverick MVD register expected")},
771 {mav_mvfx_table, 15, NULL, N_("Maverick MVFX register expected")},
772 {mav_mvdx_table, 15, NULL, N_("Maverick MVFX register expected")},
773 {mav_mvax_table, 3, NULL, N_("Maverick MVAX register expected")},
774 {mav_dspsc_table, 0, NULL, N_("Maverick DSPSC register expected")},
5a6c6817 775 {iwmmxt_table, 23, NULL, N_("Intel Wireless MMX technology register expected")},
6c43fab6
RE
776};
777
778/* Enumeration matching entries in table above. */
779enum arm_reg_type
780{
781 REG_TYPE_RN = 0,
782#define REG_TYPE_FIRST REG_TYPE_RN
783 REG_TYPE_CP = 1,
784 REG_TYPE_CN = 2,
785 REG_TYPE_FN = 3,
bfae80f2
RE
786 REG_TYPE_SN = 4,
787 REG_TYPE_DN = 5,
788 REG_TYPE_MVF = 6,
789 REG_TYPE_MVD = 7,
790 REG_TYPE_MVFX = 8,
791 REG_TYPE_MVDX = 9,
792 REG_TYPE_MVAX = 10,
793 REG_TYPE_DSPSC = 11,
e16bb312 794 REG_TYPE_IWMMXT = 12,
bfae80f2 795
e16bb312 796 REG_TYPE_MAX = 13
6c43fab6 797};
404ff6b5 798
b99bd4ef
NC
799/* Functions called by parser. */
800/* ARM instructions. */
f2b7cb0a
RE
801static void do_arit PARAMS ((char *));
802static void do_cmp PARAMS ((char *));
803static void do_mov PARAMS ((char *));
804static void do_ldst PARAMS ((char *));
805static void do_ldstt PARAMS ((char *));
806static void do_ldmstm PARAMS ((char *));
807static void do_branch PARAMS ((char *));
808static void do_swi PARAMS ((char *));
c9b604bd 809
b99bd4ef 810/* Pseudo Op codes. */
f2b7cb0a
RE
811static void do_adr PARAMS ((char *));
812static void do_adrl PARAMS ((char *));
813static void do_empty PARAMS ((char *));
c9b604bd
RE
814
815/* ARM v2. */
f2b7cb0a
RE
816static void do_mul PARAMS ((char *));
817static void do_mla PARAMS ((char *));
c9b604bd
RE
818
819/* ARM v2S. */
f2b7cb0a 820static void do_swap PARAMS ((char *));
c9b604bd
RE
821
822/* ARM v3. */
f2b7cb0a
RE
823static void do_msr PARAMS ((char *));
824static void do_mrs PARAMS ((char *));
c9b604bd
RE
825
826/* ARM v3M. */
f2b7cb0a 827static void do_mull PARAMS ((char *));
b99bd4ef 828
90e4755a 829/* ARM v4. */
f2b7cb0a 830static void do_ldstv4 PARAMS ((char *));
90e4755a 831
c9b604bd 832/* ARM v4T. */
f2b7cb0a 833static void do_bx PARAMS ((char *));
b99bd4ef 834
ea6ef066 835/* ARM v5T. */
f2b7cb0a
RE
836static void do_blx PARAMS ((char *));
837static void do_bkpt PARAMS ((char *));
838static void do_clz PARAMS ((char *));
839static void do_lstc2 PARAMS ((char *));
840static void do_cdp2 PARAMS ((char *));
841static void do_co_reg2 PARAMS ((char *));
b99bd4ef 842
ea6ef066 843/* ARM v5TExP. */
f2b7cb0a
RE
844static void do_smla PARAMS ((char *));
845static void do_smlal PARAMS ((char *));
846static void do_smul PARAMS ((char *));
847static void do_qadd PARAMS ((char *));
c9b604bd 848
ea6ef066 849/* ARM v5TE. */
f2b7cb0a
RE
850static void do_pld PARAMS ((char *));
851static void do_ldrd PARAMS ((char *));
852static void do_co_reg2c PARAMS ((char *));
b99bd4ef 853
ea6ef066
RE
854/* ARM v5TEJ. */
855static void do_bxj PARAMS ((char *));
856
b99bd4ef 857/* Coprocessor Instructions. */
f2b7cb0a
RE
858static void do_cdp PARAMS ((char *));
859static void do_lstc PARAMS ((char *));
860static void do_co_reg PARAMS ((char *));
c9b604bd
RE
861
862/* FPA instructions. */
f2b7cb0a
RE
863static void do_fpa_ctrl PARAMS ((char *));
864static void do_fpa_ldst PARAMS ((char *));
865static void do_fpa_ldmstm PARAMS ((char *));
866static void do_fpa_dyadic PARAMS ((char *));
867static void do_fpa_monadic PARAMS ((char *));
868static void do_fpa_cmp PARAMS ((char *));
869static void do_fpa_from_reg PARAMS ((char *));
870static void do_fpa_to_reg PARAMS ((char *));
c9b604bd 871
bfae80f2
RE
872/* VFP instructions. */
873static void do_vfp_sp_monadic PARAMS ((char *));
874static void do_vfp_dp_monadic PARAMS ((char *));
875static void do_vfp_sp_dyadic PARAMS ((char *));
876static void do_vfp_dp_dyadic PARAMS ((char *));
877static void do_vfp_reg_from_sp PARAMS ((char *));
878static void do_vfp_sp_from_reg PARAMS ((char *));
879static void do_vfp_sp_reg2 PARAMS ((char *));
880static void do_vfp_reg_from_dp PARAMS ((char *));
881static void do_vfp_reg2_from_dp PARAMS ((char *));
882static void do_vfp_dp_from_reg PARAMS ((char *));
883static void do_vfp_dp_from_reg2 PARAMS ((char *));
884static void do_vfp_reg_from_ctrl PARAMS ((char *));
885static void do_vfp_ctrl_from_reg PARAMS ((char *));
886static void do_vfp_sp_ldst PARAMS ((char *));
887static void do_vfp_dp_ldst PARAMS ((char *));
888static void do_vfp_sp_ldstmia PARAMS ((char *));
889static void do_vfp_sp_ldstmdb PARAMS ((char *));
890static void do_vfp_dp_ldstmia PARAMS ((char *));
891static void do_vfp_dp_ldstmdb PARAMS ((char *));
892static void do_vfp_xp_ldstmia PARAMS ((char *));
893static void do_vfp_xp_ldstmdb PARAMS ((char *));
894static void do_vfp_sp_compare_z PARAMS ((char *));
895static void do_vfp_dp_compare_z PARAMS ((char *));
896static void do_vfp_dp_sp_cvt PARAMS ((char *));
897static void do_vfp_sp_dp_cvt PARAMS ((char *));
898
c9b604bd 899/* XScale. */
63e63b07
RE
900static void do_xsc_mia PARAMS ((char *));
901static void do_xsc_mar PARAMS ((char *));
902static void do_xsc_mra PARAMS ((char *));
f2b7cb0a
RE
903
904/* Maverick. */
63e63b07 905static void do_mav_binops PARAMS ((char *, int, enum arm_reg_type,
6c43fab6 906 enum arm_reg_type));
63e63b07
RE
907static void do_mav_binops_1a PARAMS ((char *));
908static void do_mav_binops_1b PARAMS ((char *));
909static void do_mav_binops_1c PARAMS ((char *));
910static void do_mav_binops_1d PARAMS ((char *));
911static void do_mav_binops_1e PARAMS ((char *));
912static void do_mav_binops_1f PARAMS ((char *));
913static void do_mav_binops_1g PARAMS ((char *));
914static void do_mav_binops_1h PARAMS ((char *));
915static void do_mav_binops_1i PARAMS ((char *));
916static void do_mav_binops_1j PARAMS ((char *));
917static void do_mav_binops_1k PARAMS ((char *));
918static void do_mav_binops_1l PARAMS ((char *));
919static void do_mav_binops_1m PARAMS ((char *));
920static void do_mav_binops_1n PARAMS ((char *));
921static void do_mav_binops_1o PARAMS ((char *));
922static void do_mav_binops_2a PARAMS ((char *));
923static void do_mav_binops_2b PARAMS ((char *));
924static void do_mav_binops_2c PARAMS ((char *));
925static void do_mav_binops_3a PARAMS ((char *));
926static void do_mav_binops_3b PARAMS ((char *));
927static void do_mav_binops_3c PARAMS ((char *));
928static void do_mav_binops_3d PARAMS ((char *));
cc8a6dd0 929static void do_mav_triple PARAMS ((char *, int, enum arm_reg_type,
6c43fab6
RE
930 enum arm_reg_type,
931 enum arm_reg_type));
63e63b07
RE
932static void do_mav_triple_4a PARAMS ((char *));
933static void do_mav_triple_4b PARAMS ((char *));
934static void do_mav_triple_5a PARAMS ((char *));
935static void do_mav_triple_5b PARAMS ((char *));
936static void do_mav_triple_5c PARAMS ((char *));
937static void do_mav_triple_5d PARAMS ((char *));
938static void do_mav_triple_5e PARAMS ((char *));
939static void do_mav_triple_5f PARAMS ((char *));
940static void do_mav_triple_5g PARAMS ((char *));
941static void do_mav_triple_5h PARAMS ((char *));
cc8a6dd0 942static void do_mav_quad PARAMS ((char *, int, enum arm_reg_type,
6c43fab6
RE
943 enum arm_reg_type,
944 enum arm_reg_type,
945 enum arm_reg_type));
63e63b07
RE
946static void do_mav_quad_6a PARAMS ((char *));
947static void do_mav_quad_6b PARAMS ((char *));
948static void do_mav_dspsc_1 PARAMS ((char *));
949static void do_mav_dspsc_2 PARAMS ((char *));
950static void do_mav_shift PARAMS ((char *, enum arm_reg_type,
6c43fab6 951 enum arm_reg_type));
63e63b07
RE
952static void do_mav_shift_1 PARAMS ((char *));
953static void do_mav_shift_2 PARAMS ((char *));
954static void do_mav_ldst PARAMS ((char *, enum arm_reg_type));
955static void do_mav_ldst_1 PARAMS ((char *));
956static void do_mav_ldst_2 PARAMS ((char *));
957static void do_mav_ldst_3 PARAMS ((char *));
958static void do_mav_ldst_4 PARAMS ((char *));
959
960static int mav_reg_required_here PARAMS ((char **, int,
6c43fab6 961 enum arm_reg_type));
63e63b07 962static int mav_parse_offset PARAMS ((char **, int *));
404ff6b5 963
90e4755a
RE
964static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *,
965 int, int));
6c43fab6
RE
966static int arm_reg_parse PARAMS ((char **, struct hash_control *));
967static enum arm_reg_type arm_reg_parse_any PARAMS ((char *));
05d2d07e 968static const struct asm_psr * arm_psr_parse PARAMS ((char **));
90e4755a
RE
969static void symbol_locate PARAMS ((symbolS *, const char *, segT, valueT,
970 fragS *));
b99bd4ef
NC
971static int add_to_lit_pool PARAMS ((void));
972static unsigned validate_immediate PARAMS ((unsigned));
90e4755a
RE
973static unsigned validate_immediate_twopart PARAMS ((unsigned int,
974 unsigned int *));
b99bd4ef
NC
975static int validate_offset_imm PARAMS ((unsigned int, int));
976static void opcode_select PARAMS ((int));
977static void end_of_line PARAMS ((char *));
978static int reg_required_here PARAMS ((char **, int));
979static int psr_required_here PARAMS ((char **));
980static int co_proc_number PARAMS ((char **));
981static int cp_opc_expr PARAMS ((char **, int, int));
982static int cp_reg_required_here PARAMS ((char **, int));
983static int fp_reg_required_here PARAMS ((char **, int));
bfae80f2
RE
984static int vfp_sp_reg_required_here PARAMS ((char **, enum vfp_sp_reg_pos));
985static int vfp_dp_reg_required_here PARAMS ((char **, enum vfp_dp_reg_pos));
986static void vfp_sp_ldstm PARAMS ((char *, enum vfp_ldstm_type));
987static void vfp_dp_ldstm PARAMS ((char *, enum vfp_ldstm_type));
988static long vfp_sp_reg_list PARAMS ((char **, enum vfp_sp_reg_pos));
989static long vfp_dp_reg_list PARAMS ((char **));
990static int vfp_psr_required_here PARAMS ((char **str));
991static const struct vfp_reg *vfp_psr_parse PARAMS ((char **str));
b99bd4ef 992static int cp_address_offset PARAMS ((char **));
bfae80f2 993static int cp_address_required_here PARAMS ((char **, int));
b99bd4ef
NC
994static int my_get_float_expression PARAMS ((char **));
995static int skip_past_comma PARAMS ((char **));
996static int walk_no_bignums PARAMS ((symbolS *));
997static int negate_data_op PARAMS ((unsigned long *, unsigned long));
998static int data_op2 PARAMS ((char **));
999static int fp_op2 PARAMS ((char **));
1000static long reg_list PARAMS ((char **));
1001static void thumb_load_store PARAMS ((char *, int, int));
1002static int decode_shift PARAMS ((char **, int));
90e4755a
RE
1003static int ldst_extend PARAMS ((char **));
1004static int ldst_extend_v4 PARAMS ((char **));
b99bd4ef 1005static void thumb_add_sub PARAMS ((char *, int));
6c43fab6
RE
1006static void insert_reg PARAMS ((const struct reg_entry *,
1007 struct hash_control *));
b99bd4ef
NC
1008static void thumb_shift PARAMS ((char *, int));
1009static void thumb_mov_compare PARAMS ((char *, int));
f2b7cb0a 1010static void build_arm_ops_hsh PARAMS ((void));
b99bd4ef
NC
1011static void set_constant_flonums PARAMS ((void));
1012static valueT md_chars_to_number PARAMS ((char *, int));
6c43fab6
RE
1013static void build_reg_hsh PARAMS ((struct reg_map *));
1014static void insert_reg_alias PARAMS ((char *, int, struct hash_control *));
1015static int create_register_alias PARAMS ((char *, char *));
f03698e6 1016static void output_inst PARAMS ((const char *));
2c20dfb2
NC
1017static int accum0_required_here PARAMS ((char **));
1018static int ld_mode_required_here PARAMS ((char **));
f2b7cb0a 1019static void do_branch25 PARAMS ((char *));
2c20dfb2 1020static symbolS * find_real_start PARAMS ((symbolS *));
b99bd4ef
NC
1021#ifdef OBJ_ELF
1022static bfd_reloc_code_real_type arm_parse_reloc PARAMS ((void));
1023#endif
1024
e16bb312
NC
1025static int wreg_required_here PARAMS ((char **, int, enum wreg_type));
1026static void do_iwmmxt_byte_addr PARAMS ((char *));
1027static void do_iwmmxt_tandc PARAMS ((char *));
1028static void do_iwmmxt_tbcst PARAMS ((char *));
1029static void do_iwmmxt_textrc PARAMS ((char *));
1030static void do_iwmmxt_textrm PARAMS ((char *));
1031static void do_iwmmxt_tinsr PARAMS ((char *));
1032static void do_iwmmxt_tmcr PARAMS ((char *));
1033static void do_iwmmxt_tmcrr PARAMS ((char *));
1034static void do_iwmmxt_tmia PARAMS ((char *));
1035static void do_iwmmxt_tmovmsk PARAMS ((char *));
1036static void do_iwmmxt_tmrc PARAMS ((char *));
1037static void do_iwmmxt_tmrrc PARAMS ((char *));
1038static void do_iwmmxt_torc PARAMS ((char *));
1039static void do_iwmmxt_waligni PARAMS ((char *));
1040static void do_iwmmxt_wmov PARAMS ((char *));
1041static void do_iwmmxt_word_addr PARAMS ((char *));
1042static void do_iwmmxt_wrwr PARAMS ((char *));
1043static void do_iwmmxt_wrwrwcg PARAMS ((char *));
1044static void do_iwmmxt_wrwrwr PARAMS ((char *));
1045static void do_iwmmxt_wshufh PARAMS ((char *));
1046static void do_iwmmxt_wzero PARAMS ((char *));
1047static int cp_byte_address_offset PARAMS ((char **));
1048static int cp_byte_address_required_here PARAMS ((char **));
1049
b99bd4ef
NC
1050/* ARM instructions take 4bytes in the object file, Thumb instructions
1051 take 2: */
1052#define INSN_SIZE 4
1053
404ff6b5 1054/* "INSN<cond> X,Y" where X:bit12, Y:bit16. */
63e63b07 1055#define MAV_MODE1 0x100c
404ff6b5
AH
1056
1057/* "INSN<cond> X,Y" where X:bit16, Y:bit12. */
63e63b07 1058#define MAV_MODE2 0x0c10
404ff6b5
AH
1059
1060/* "INSN<cond> X,Y" where X:0, Y:bit16. */
63e63b07 1061#define MAV_MODE3 0x1000
404ff6b5
AH
1062
1063/* "INSN<cond> X,Y,Z" where X:16, Y:0, Z:12. */
63e63b07 1064#define MAV_MODE4 0x0c0010
404ff6b5
AH
1065
1066/* "INSN<cond> X,Y,Z" where X:12, Y:16, Z:0. */
63e63b07 1067#define MAV_MODE5 0x00100c
404ff6b5
AH
1068
1069/* "INSN<cond> W,X,Y,Z" where W:5, X:12, Y:16, Z:0. */
63e63b07 1070#define MAV_MODE6 0x00100c05
b99bd4ef
NC
1071
1072struct asm_opcode
1073{
1074 /* Basic string to match. */
05d2d07e 1075 const char * template;
b99bd4ef
NC
1076
1077 /* Basic instruction code. */
1078 unsigned long value;
1079
90e4755a
RE
1080 /* Offset into the template where the condition code (if any) will be.
1081 If zero, then the instruction is never conditional. */
1082 unsigned cond_offset;
b99bd4ef 1083
90e4755a
RE
1084 /* Which architecture variant provides this instruction. */
1085 unsigned long variant;
b99bd4ef
NC
1086
1087 /* Function to call to parse args. */
f2b7cb0a 1088 void (* parms) PARAMS ((char *));
b99bd4ef
NC
1089};
1090
05d2d07e 1091static const struct asm_opcode insns[] =
b99bd4ef 1092{
c9b604bd 1093 /* Core ARM Instructions. */
90e4755a
RE
1094 {"and", 0xe0000000, 3, ARM_EXT_V1, do_arit},
1095 {"ands", 0xe0100000, 3, ARM_EXT_V1, do_arit},
1096 {"eor", 0xe0200000, 3, ARM_EXT_V1, do_arit},
1097 {"eors", 0xe0300000, 3, ARM_EXT_V1, do_arit},
1098 {"sub", 0xe0400000, 3, ARM_EXT_V1, do_arit},
1099 {"subs", 0xe0500000, 3, ARM_EXT_V1, do_arit},
1100 {"rsb", 0xe0600000, 3, ARM_EXT_V1, do_arit},
1101 {"rsbs", 0xe0700000, 3, ARM_EXT_V1, do_arit},
1102 {"add", 0xe0800000, 3, ARM_EXT_V1, do_arit},
1103 {"adds", 0xe0900000, 3, ARM_EXT_V1, do_arit},
1104 {"adc", 0xe0a00000, 3, ARM_EXT_V1, do_arit},
1105 {"adcs", 0xe0b00000, 3, ARM_EXT_V1, do_arit},
1106 {"sbc", 0xe0c00000, 3, ARM_EXT_V1, do_arit},
1107 {"sbcs", 0xe0d00000, 3, ARM_EXT_V1, do_arit},
1108 {"rsc", 0xe0e00000, 3, ARM_EXT_V1, do_arit},
1109 {"rscs", 0xe0f00000, 3, ARM_EXT_V1, do_arit},
1110 {"orr", 0xe1800000, 3, ARM_EXT_V1, do_arit},
1111 {"orrs", 0xe1900000, 3, ARM_EXT_V1, do_arit},
1112 {"bic", 0xe1c00000, 3, ARM_EXT_V1, do_arit},
1113 {"bics", 0xe1d00000, 3, ARM_EXT_V1, do_arit},
1114
1115 {"tst", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
1116 {"tsts", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
1117 {"tstp", 0xe110f000, 3, ARM_EXT_V1, do_cmp},
1118 {"teq", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
1119 {"teqs", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
1120 {"teqp", 0xe130f000, 3, ARM_EXT_V1, do_cmp},
1121 {"cmp", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
1122 {"cmps", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
1123 {"cmpp", 0xe150f000, 3, ARM_EXT_V1, do_cmp},
1124 {"cmn", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
1125 {"cmns", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
1126 {"cmnp", 0xe170f000, 3, ARM_EXT_V1, do_cmp},
1127
1128 {"mov", 0xe1a00000, 3, ARM_EXT_V1, do_mov},
1129 {"movs", 0xe1b00000, 3, ARM_EXT_V1, do_mov},
1130 {"mvn", 0xe1e00000, 3, ARM_EXT_V1, do_mov},
1131 {"mvns", 0xe1f00000, 3, ARM_EXT_V1, do_mov},
1132
1133 {"ldr", 0xe4100000, 3, ARM_EXT_V1, do_ldst},
1134 {"ldrb", 0xe4500000, 3, ARM_EXT_V1, do_ldst},
1135 {"ldrt", 0xe4300000, 3, ARM_EXT_V1, do_ldstt},
1136 {"ldrbt", 0xe4700000, 3, ARM_EXT_V1, do_ldstt},
1137 {"str", 0xe4000000, 3, ARM_EXT_V1, do_ldst},
1138 {"strb", 0xe4400000, 3, ARM_EXT_V1, do_ldst},
1139 {"strt", 0xe4200000, 3, ARM_EXT_V1, do_ldstt},
1140 {"strbt", 0xe4600000, 3, ARM_EXT_V1, do_ldstt},
1141
1142 {"stmia", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
1143 {"stmib", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
1144 {"stmda", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
1145 {"stmdb", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
1146 {"stmfd", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
1147 {"stmfa", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
1148 {"stmea", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
1149 {"stmed", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
1150
1151 {"ldmia", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
1152 {"ldmib", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
1153 {"ldmda", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
1154 {"ldmdb", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
1155 {"ldmfd", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
1156 {"ldmfa", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
1157 {"ldmea", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
1158 {"ldmed", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
1159
1160 {"swi", 0xef000000, 3, ARM_EXT_V1, do_swi},
b99bd4ef 1161#ifdef TE_WINCE
c9b604bd 1162 /* XXX This is the wrong place to do this. Think multi-arch. */
90e4755a
RE
1163 {"bl", 0xeb000000, 2, ARM_EXT_V1, do_branch},
1164 {"b", 0xea000000, 1, ARM_EXT_V1, do_branch},
b99bd4ef 1165#else
90e4755a
RE
1166 {"bl", 0xebfffffe, 2, ARM_EXT_V1, do_branch},
1167 {"b", 0xeafffffe, 1, ARM_EXT_V1, do_branch},
b99bd4ef
NC
1168#endif
1169
c9b604bd 1170 /* Pseudo ops. */
90e4755a
RE
1171 {"adr", 0xe28f0000, 3, ARM_EXT_V1, do_adr},
1172 {"adrl", 0xe28f0000, 3, ARM_EXT_V1, do_adrl},
1173 {"nop", 0xe1a00000, 3, ARM_EXT_V1, do_empty},
b99bd4ef 1174
c9b604bd 1175 /* ARM 2 multiplies. */
90e4755a
RE
1176 {"mul", 0xe0000090, 3, ARM_EXT_V2, do_mul},
1177 {"muls", 0xe0100090, 3, ARM_EXT_V2, do_mul},
1178 {"mla", 0xe0200090, 3, ARM_EXT_V2, do_mla},
1179 {"mlas", 0xe0300090, 3, ARM_EXT_V2, do_mla},
b99bd4ef 1180
c9b604bd 1181 /* Generic copressor instructions. */
90e4755a
RE
1182 {"cdp", 0xee000000, 3, ARM_EXT_V2, do_cdp},
1183 {"ldc", 0xec100000, 3, ARM_EXT_V2, do_lstc},
1184 {"ldcl", 0xec500000, 3, ARM_EXT_V2, do_lstc},
1185 {"stc", 0xec000000, 3, ARM_EXT_V2, do_lstc},
1186 {"stcl", 0xec400000, 3, ARM_EXT_V2, do_lstc},
1187 {"mcr", 0xee000010, 3, ARM_EXT_V2, do_co_reg},
1188 {"mrc", 0xee100010, 3, ARM_EXT_V2, do_co_reg},
c9b604bd
RE
1189
1190 /* ARM 3 - swp instructions. */
90e4755a
RE
1191 {"swp", 0xe1000090, 3, ARM_EXT_V2S, do_swap},
1192 {"swpb", 0xe1400090, 3, ARM_EXT_V2S, do_swap},
b99bd4ef 1193
c9b604bd 1194 /* ARM 6 Status register instructions. */
90e4755a
RE
1195 {"mrs", 0xe10f0000, 3, ARM_EXT_V3, do_mrs},
1196 {"msr", 0xe120f000, 3, ARM_EXT_V3, do_msr},
1197 /* ScottB: our code uses 0xe128f000 for msr.
c9b604bd 1198 NickC: but this is wrong because the bits 16 through 19 are
90e4755a 1199 handled by the PSR_xxx defines above. */
b99bd4ef 1200
f2b7cb0a 1201 /* ARM 7M long multiplies. */
90e4755a
RE
1202 {"smull", 0xe0c00090, 5, ARM_EXT_V3M, do_mull},
1203 {"smulls", 0xe0d00090, 5, ARM_EXT_V3M, do_mull},
1204 {"umull", 0xe0800090, 5, ARM_EXT_V3M, do_mull},
1205 {"umulls", 0xe0900090, 5, ARM_EXT_V3M, do_mull},
1206 {"smlal", 0xe0e00090, 5, ARM_EXT_V3M, do_mull},
1207 {"smlals", 0xe0f00090, 5, ARM_EXT_V3M, do_mull},
1208 {"umlal", 0xe0a00090, 5, ARM_EXT_V3M, do_mull},
1209 {"umlals", 0xe0b00090, 5, ARM_EXT_V3M, do_mull},
1210
1211 /* ARM Architecture 4. */
1212 {"ldrh", 0xe01000b0, 3, ARM_EXT_V4, do_ldstv4},
1213 {"ldrsh", 0xe01000f0, 3, ARM_EXT_V4, do_ldstv4},
1214 {"ldrsb", 0xe01000d0, 3, ARM_EXT_V4, do_ldstv4},
1215 {"strh", 0xe00000b0, 3, ARM_EXT_V4, do_ldstv4},
b99bd4ef 1216
c9b604bd 1217 /* ARM Architecture 4T. */
cc8a6dd0 1218 /* Note: bx (and blx) are required on V5, even if the processor does
90e4755a
RE
1219 not support Thumb. */
1220 {"bx", 0xe12fff10, 2, ARM_EXT_V4T | ARM_EXT_V5, do_bx},
1221
ea6ef066 1222 /* ARM Architecture 5T. */
90e4755a
RE
1223 /* Note: blx has 2 variants, so the .value is set dynamically.
1224 Only one of the variants has conditional execution. */
1225 {"blx", 0xe0000000, 3, ARM_EXT_V5, do_blx},
1226 {"clz", 0xe16f0f10, 3, ARM_EXT_V5, do_clz},
1227 {"bkpt", 0xe1200070, 0, ARM_EXT_V5, do_bkpt},
1228 {"ldc2", 0xfc100000, 0, ARM_EXT_V5, do_lstc2},
1229 {"ldc2l", 0xfc500000, 0, ARM_EXT_V5, do_lstc2},
1230 {"stc2", 0xfc000000, 0, ARM_EXT_V5, do_lstc2},
1231 {"stc2l", 0xfc400000, 0, ARM_EXT_V5, do_lstc2},
1232 {"cdp2", 0xfe000000, 0, ARM_EXT_V5, do_cdp2},
1233 {"mcr2", 0xfe000010, 0, ARM_EXT_V5, do_co_reg2},
1234 {"mrc2", 0xfe100010, 0, ARM_EXT_V5, do_co_reg2},
1235
ea6ef066 1236 /* ARM Architecture 5TExP. */
90e4755a
RE
1237 {"smlabb", 0xe1000080, 6, ARM_EXT_V5ExP, do_smla},
1238 {"smlatb", 0xe10000a0, 6, ARM_EXT_V5ExP, do_smla},
1239 {"smlabt", 0xe10000c0, 6, ARM_EXT_V5ExP, do_smla},
1240 {"smlatt", 0xe10000e0, 6, ARM_EXT_V5ExP, do_smla},
1241
1242 {"smlawb", 0xe1200080, 6, ARM_EXT_V5ExP, do_smla},
1243 {"smlawt", 0xe12000c0, 6, ARM_EXT_V5ExP, do_smla},
1244
1245 {"smlalbb", 0xe1400080, 7, ARM_EXT_V5ExP, do_smlal},
1246 {"smlaltb", 0xe14000a0, 7, ARM_EXT_V5ExP, do_smlal},
1247 {"smlalbt", 0xe14000c0, 7, ARM_EXT_V5ExP, do_smlal},
1248 {"smlaltt", 0xe14000e0, 7, ARM_EXT_V5ExP, do_smlal},
1249
1250 {"smulbb", 0xe1600080, 6, ARM_EXT_V5ExP, do_smul},
1251 {"smultb", 0xe16000a0, 6, ARM_EXT_V5ExP, do_smul},
1252 {"smulbt", 0xe16000c0, 6, ARM_EXT_V5ExP, do_smul},
1253 {"smultt", 0xe16000e0, 6, ARM_EXT_V5ExP, do_smul},
1254
1255 {"smulwb", 0xe12000a0, 6, ARM_EXT_V5ExP, do_smul},
1256 {"smulwt", 0xe12000e0, 6, ARM_EXT_V5ExP, do_smul},
1257
1258 {"qadd", 0xe1000050, 4, ARM_EXT_V5ExP, do_qadd},
1259 {"qdadd", 0xe1400050, 5, ARM_EXT_V5ExP, do_qadd},
1260 {"qsub", 0xe1200050, 4, ARM_EXT_V5ExP, do_qadd},
1261 {"qdsub", 0xe1600050, 5, ARM_EXT_V5ExP, do_qadd},
c9b604bd 1262
ea6ef066 1263 /* ARM Architecture 5TE. */
90e4755a
RE
1264 {"pld", 0xf450f000, 0, ARM_EXT_V5E, do_pld},
1265 {"ldrd", 0xe00000d0, 3, ARM_EXT_V5E, do_ldrd},
1266 {"strd", 0xe00000f0, 3, ARM_EXT_V5E, do_ldrd},
1267
1268 {"mcrr", 0xec400000, 4, ARM_EXT_V5E, do_co_reg2c},
1269 {"mrrc", 0xec500000, 4, ARM_EXT_V5E, do_co_reg2c},
404ff6b5 1270
ea6ef066
RE
1271 /* ARM Architecture 5TEJ. */
1272 {"bxj", 0xe12fff20, 3, ARM_EXT_V5J, do_bxj},
1273
c9b604bd 1274 /* Core FPA instruction set (V1). */
90e4755a
RE
1275 {"wfs", 0xee200110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1276 {"rfs", 0xee300110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1277 {"wfc", 0xee400110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1278 {"rfc", 0xee500110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
1279
1280 {"ldfs", 0xec100100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1281 {"ldfd", 0xec108100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1282 {"ldfe", 0xec500100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1283 {"ldfp", 0xec508100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1284
1285 {"stfs", 0xec000100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1286 {"stfd", 0xec008100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1287 {"stfe", 0xec400100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1288 {"stfp", 0xec408100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
1289
1290 {"mvfs", 0xee008100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1291 {"mvfsp", 0xee008120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1292 {"mvfsm", 0xee008140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1293 {"mvfsz", 0xee008160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1294 {"mvfd", 0xee008180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1295 {"mvfdp", 0xee0081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1296 {"mvfdm", 0xee0081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1297 {"mvfdz", 0xee0081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1298 {"mvfe", 0xee088100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1299 {"mvfep", 0xee088120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1300 {"mvfem", 0xee088140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1301 {"mvfez", 0xee088160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1302
1303 {"mnfs", 0xee108100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1304 {"mnfsp", 0xee108120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1305 {"mnfsm", 0xee108140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1306 {"mnfsz", 0xee108160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1307 {"mnfd", 0xee108180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1308 {"mnfdp", 0xee1081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1309 {"mnfdm", 0xee1081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1310 {"mnfdz", 0xee1081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1311 {"mnfe", 0xee188100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1312 {"mnfep", 0xee188120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1313 {"mnfem", 0xee188140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1314 {"mnfez", 0xee188160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1315
1316 {"abss", 0xee208100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1317 {"abssp", 0xee208120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1318 {"abssm", 0xee208140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1319 {"abssz", 0xee208160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1320 {"absd", 0xee208180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1321 {"absdp", 0xee2081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1322 {"absdm", 0xee2081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1323 {"absdz", 0xee2081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1324 {"abse", 0xee288100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1325 {"absep", 0xee288120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1326 {"absem", 0xee288140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1327 {"absez", 0xee288160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1328
1329 {"rnds", 0xee308100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1330 {"rndsp", 0xee308120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1331 {"rndsm", 0xee308140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1332 {"rndsz", 0xee308160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1333 {"rndd", 0xee308180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1334 {"rnddp", 0xee3081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1335 {"rnddm", 0xee3081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1336 {"rnddz", 0xee3081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1337 {"rnde", 0xee388100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1338 {"rndep", 0xee388120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1339 {"rndem", 0xee388140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1340 {"rndez", 0xee388160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1341
1342 {"sqts", 0xee408100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1343 {"sqtsp", 0xee408120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1344 {"sqtsm", 0xee408140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1345 {"sqtsz", 0xee408160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1346 {"sqtd", 0xee408180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1347 {"sqtdp", 0xee4081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1348 {"sqtdm", 0xee4081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1349 {"sqtdz", 0xee4081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1350 {"sqte", 0xee488100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1351 {"sqtep", 0xee488120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1352 {"sqtem", 0xee488140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1353 {"sqtez", 0xee488160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1354
1355 {"logs", 0xee508100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1356 {"logsp", 0xee508120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1357 {"logsm", 0xee508140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1358 {"logsz", 0xee508160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1359 {"logd", 0xee508180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1360 {"logdp", 0xee5081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1361 {"logdm", 0xee5081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1362 {"logdz", 0xee5081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1363 {"loge", 0xee588100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1364 {"logep", 0xee588120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1365 {"logem", 0xee588140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1366 {"logez", 0xee588160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1367
1368 {"lgns", 0xee608100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1369 {"lgnsp", 0xee608120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1370 {"lgnsm", 0xee608140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1371 {"lgnsz", 0xee608160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1372 {"lgnd", 0xee608180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1373 {"lgndp", 0xee6081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1374 {"lgndm", 0xee6081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1375 {"lgndz", 0xee6081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1376 {"lgne", 0xee688100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1377 {"lgnep", 0xee688120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1378 {"lgnem", 0xee688140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1379 {"lgnez", 0xee688160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1380
1381 {"exps", 0xee708100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1382 {"expsp", 0xee708120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1383 {"expsm", 0xee708140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1384 {"expsz", 0xee708160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1385 {"expd", 0xee708180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1386 {"expdp", 0xee7081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1387 {"expdm", 0xee7081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1388 {"expdz", 0xee7081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1389 {"expe", 0xee788100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1390 {"expep", 0xee788120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1391 {"expem", 0xee788140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1392 {"expdz", 0xee788160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1393
1394 {"sins", 0xee808100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1395 {"sinsp", 0xee808120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1396 {"sinsm", 0xee808140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1397 {"sinsz", 0xee808160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1398 {"sind", 0xee808180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1399 {"sindp", 0xee8081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1400 {"sindm", 0xee8081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1401 {"sindz", 0xee8081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1402 {"sine", 0xee888100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1403 {"sinep", 0xee888120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1404 {"sinem", 0xee888140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1405 {"sinez", 0xee888160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1406
1407 {"coss", 0xee908100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1408 {"cossp", 0xee908120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1409 {"cossm", 0xee908140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1410 {"cossz", 0xee908160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1411 {"cosd", 0xee908180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1412 {"cosdp", 0xee9081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1413 {"cosdm", 0xee9081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1414 {"cosdz", 0xee9081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1415 {"cose", 0xee988100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1416 {"cosep", 0xee988120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1417 {"cosem", 0xee988140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1418 {"cosez", 0xee988160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1419
1420 {"tans", 0xeea08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1421 {"tansp", 0xeea08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1422 {"tansm", 0xeea08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1423 {"tansz", 0xeea08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1424 {"tand", 0xeea08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1425 {"tandp", 0xeea081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1426 {"tandm", 0xeea081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1427 {"tandz", 0xeea081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1428 {"tane", 0xeea88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1429 {"tanep", 0xeea88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1430 {"tanem", 0xeea88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1431 {"tanez", 0xeea88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1432
1433 {"asns", 0xeeb08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1434 {"asnsp", 0xeeb08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1435 {"asnsm", 0xeeb08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1436 {"asnsz", 0xeeb08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1437 {"asnd", 0xeeb08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1438 {"asndp", 0xeeb081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1439 {"asndm", 0xeeb081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1440 {"asndz", 0xeeb081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1441 {"asne", 0xeeb88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1442 {"asnep", 0xeeb88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1443 {"asnem", 0xeeb88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1444 {"asnez", 0xeeb88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1445
1446 {"acss", 0xeec08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1447 {"acssp", 0xeec08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1448 {"acssm", 0xeec08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1449 {"acssz", 0xeec08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1450 {"acsd", 0xeec08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1451 {"acsdp", 0xeec081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1452 {"acsdm", 0xeec081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1453 {"acsdz", 0xeec081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1454 {"acse", 0xeec88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1455 {"acsep", 0xeec88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1456 {"acsem", 0xeec88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1457 {"acsez", 0xeec88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1458
1459 {"atns", 0xeed08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1460 {"atnsp", 0xeed08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1461 {"atnsm", 0xeed08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1462 {"atnsz", 0xeed08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1463 {"atnd", 0xeed08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1464 {"atndp", 0xeed081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1465 {"atndm", 0xeed081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1466 {"atndz", 0xeed081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1467 {"atne", 0xeed88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1468 {"atnep", 0xeed88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1469 {"atnem", 0xeed88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1470 {"atnez", 0xeed88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1471
1472 {"urds", 0xeee08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1473 {"urdsp", 0xeee08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1474 {"urdsm", 0xeee08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1475 {"urdsz", 0xeee08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1476 {"urdd", 0xeee08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1477 {"urddp", 0xeee081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1478 {"urddm", 0xeee081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1479 {"urddz", 0xeee081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1480 {"urde", 0xeee88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1481 {"urdep", 0xeee88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1482 {"urdem", 0xeee88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1483 {"urdez", 0xeee88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1484
1485 {"nrms", 0xeef08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1486 {"nrmsp", 0xeef08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1487 {"nrmsm", 0xeef08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1488 {"nrmsz", 0xeef08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1489 {"nrmd", 0xeef08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1490 {"nrmdp", 0xeef081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1491 {"nrmdm", 0xeef081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1492 {"nrmdz", 0xeef081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1493 {"nrme", 0xeef88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1494 {"nrmep", 0xeef88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1495 {"nrmem", 0xeef88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1496 {"nrmez", 0xeef88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
1497
1498 {"adfs", 0xee000100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1499 {"adfsp", 0xee000120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1500 {"adfsm", 0xee000140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1501 {"adfsz", 0xee000160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1502 {"adfd", 0xee000180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1503 {"adfdp", 0xee0001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1504 {"adfdm", 0xee0001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1505 {"adfdz", 0xee0001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1506 {"adfe", 0xee080100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1507 {"adfep", 0xee080120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1508 {"adfem", 0xee080140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1509 {"adfez", 0xee080160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1510
1511 {"sufs", 0xee200100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1512 {"sufsp", 0xee200120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1513 {"sufsm", 0xee200140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1514 {"sufsz", 0xee200160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1515 {"sufd", 0xee200180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1516 {"sufdp", 0xee2001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1517 {"sufdm", 0xee2001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1518 {"sufdz", 0xee2001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1519 {"sufe", 0xee280100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1520 {"sufep", 0xee280120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1521 {"sufem", 0xee280140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1522 {"sufez", 0xee280160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1523
1524 {"rsfs", 0xee300100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1525 {"rsfsp", 0xee300120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1526 {"rsfsm", 0xee300140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1527 {"rsfsz", 0xee300160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1528 {"rsfd", 0xee300180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1529 {"rsfdp", 0xee3001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1530 {"rsfdm", 0xee3001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1531 {"rsfdz", 0xee3001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1532 {"rsfe", 0xee380100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1533 {"rsfep", 0xee380120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1534 {"rsfem", 0xee380140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1535 {"rsfez", 0xee380160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1536
1537 {"mufs", 0xee100100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1538 {"mufsp", 0xee100120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1539 {"mufsm", 0xee100140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1540 {"mufsz", 0xee100160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1541 {"mufd", 0xee100180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1542 {"mufdp", 0xee1001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1543 {"mufdm", 0xee1001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1544 {"mufdz", 0xee1001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1545 {"mufe", 0xee180100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1546 {"mufep", 0xee180120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1547 {"mufem", 0xee180140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1548 {"mufez", 0xee180160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1549
1550 {"dvfs", 0xee400100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1551 {"dvfsp", 0xee400120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1552 {"dvfsm", 0xee400140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1553 {"dvfsz", 0xee400160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1554 {"dvfd", 0xee400180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1555 {"dvfdp", 0xee4001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1556 {"dvfdm", 0xee4001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1557 {"dvfdz", 0xee4001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1558 {"dvfe", 0xee480100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1559 {"dvfep", 0xee480120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1560 {"dvfem", 0xee480140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1561 {"dvfez", 0xee480160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1562
1563 {"rdfs", 0xee500100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1564 {"rdfsp", 0xee500120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1565 {"rdfsm", 0xee500140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1566 {"rdfsz", 0xee500160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1567 {"rdfd", 0xee500180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1568 {"rdfdp", 0xee5001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1569 {"rdfdm", 0xee5001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1570 {"rdfdz", 0xee5001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1571 {"rdfe", 0xee580100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1572 {"rdfep", 0xee580120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1573 {"rdfem", 0xee580140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1574 {"rdfez", 0xee580160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1575
1576 {"pows", 0xee600100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1577 {"powsp", 0xee600120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1578 {"powsm", 0xee600140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1579 {"powsz", 0xee600160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1580 {"powd", 0xee600180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1581 {"powdp", 0xee6001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1582 {"powdm", 0xee6001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1583 {"powdz", 0xee6001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1584 {"powe", 0xee680100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1585 {"powep", 0xee680120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1586 {"powem", 0xee680140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1587 {"powez", 0xee680160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1588
1589 {"rpws", 0xee700100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1590 {"rpwsp", 0xee700120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1591 {"rpwsm", 0xee700140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1592 {"rpwsz", 0xee700160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1593 {"rpwd", 0xee700180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1594 {"rpwdp", 0xee7001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1595 {"rpwdm", 0xee7001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1596 {"rpwdz", 0xee7001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1597 {"rpwe", 0xee780100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1598 {"rpwep", 0xee780120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1599 {"rpwem", 0xee780140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1600 {"rpwez", 0xee780160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1601
1602 {"rmfs", 0xee800100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1603 {"rmfsp", 0xee800120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1604 {"rmfsm", 0xee800140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1605 {"rmfsz", 0xee800160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1606 {"rmfd", 0xee800180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1607 {"rmfdp", 0xee8001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1608 {"rmfdm", 0xee8001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1609 {"rmfdz", 0xee8001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1610 {"rmfe", 0xee880100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1611 {"rmfep", 0xee880120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1612 {"rmfem", 0xee880140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1613 {"rmfez", 0xee880160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1614
1615 {"fmls", 0xee900100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1616 {"fmlsp", 0xee900120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1617 {"fmlsm", 0xee900140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1618 {"fmlsz", 0xee900160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1619 {"fmld", 0xee900180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1620 {"fmldp", 0xee9001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1621 {"fmldm", 0xee9001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1622 {"fmldz", 0xee9001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1623 {"fmle", 0xee980100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1624 {"fmlep", 0xee980120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1625 {"fmlem", 0xee980140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1626 {"fmlez", 0xee980160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1627
1628 {"fdvs", 0xeea00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1629 {"fdvsp", 0xeea00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1630 {"fdvsm", 0xeea00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1631 {"fdvsz", 0xeea00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1632 {"fdvd", 0xeea00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1633 {"fdvdp", 0xeea001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1634 {"fdvdm", 0xeea001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1635 {"fdvdz", 0xeea001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1636 {"fdve", 0xeea80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1637 {"fdvep", 0xeea80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1638 {"fdvem", 0xeea80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1639 {"fdvez", 0xeea80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1640
1641 {"frds", 0xeeb00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1642 {"frdsp", 0xeeb00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1643 {"frdsm", 0xeeb00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1644 {"frdsz", 0xeeb00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1645 {"frdd", 0xeeb00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1646 {"frddp", 0xeeb001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1647 {"frddm", 0xeeb001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1648 {"frddz", 0xeeb001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1649 {"frde", 0xeeb80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1650 {"frdep", 0xeeb80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1651 {"frdem", 0xeeb80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1652 {"frdez", 0xeeb80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1653
1654 {"pols", 0xeec00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1655 {"polsp", 0xeec00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1656 {"polsm", 0xeec00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1657 {"polsz", 0xeec00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1658 {"pold", 0xeec00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1659 {"poldp", 0xeec001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1660 {"poldm", 0xeec001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1661 {"poldz", 0xeec001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1662 {"pole", 0xeec80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1663 {"polep", 0xeec80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1664 {"polem", 0xeec80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1665 {"polez", 0xeec80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
1666
1667 {"cmf", 0xee90f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1668 {"cmfe", 0xeed0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1669 {"cnf", 0xeeb0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1670 {"cnfe", 0xeef0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
1671 /* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should
1672 not be an optional suffix, but part of the instruction. To be
1673 compatible, we accept either. */
1674 {"cmfe", 0xeed0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
1675 {"cnfe", 0xeef0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
1676
1677 {"flts", 0xee000110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1678 {"fltsp", 0xee000130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1679 {"fltsm", 0xee000150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1680 {"fltsz", 0xee000170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1681 {"fltd", 0xee000190, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1682 {"fltdp", 0xee0001b0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1683 {"fltdm", 0xee0001d0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1684 {"fltdz", 0xee0001f0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1685 {"flte", 0xee080110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1686 {"fltep", 0xee080130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1687 {"fltem", 0xee080150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1688 {"fltez", 0xee080170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
1689
1690 /* The implementation of the FIX instruction is broken on some
1691 assemblers, in that it accepts a precision specifier as well as a
1692 rounding specifier, despite the fact that this is meaningless.
1693 To be more compatible, we accept it as well, though of course it
1694 does not set any bits. */
1695 {"fix", 0xee100110, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1696 {"fixp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1697 {"fixm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1698 {"fixz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1699 {"fixsp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1700 {"fixsm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1701 {"fixsz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1702 {"fixdp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1703 {"fixdm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1704 {"fixdz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1705 {"fixep", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1706 {"fixem", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
1707 {"fixez", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
c9b604bd
RE
1708
1709 /* Instructions that were new with the real FPA, call them V2. */
90e4755a
RE
1710 {"lfm", 0xec100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1711 {"lfmfd", 0xec900200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1712 {"lfmea", 0xed100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1713 {"sfm", 0xec000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1714 {"sfmfd", 0xed000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
1715 {"sfmea", 0xec800200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
c9b604bd 1716
bfae80f2
RE
1717 /* VFP V1xD (single precision). */
1718 /* Moves and type conversions. */
1719 {"fcpys", 0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1720 {"fmrs", 0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp},
1721 {"fmsr", 0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg},
1722 {"fmstat", 0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty},
1723 {"fsitos", 0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1724 {"fuitos", 0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1725 {"ftosis", 0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1726 {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1727 {"ftouis", 0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1728 {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1729 {"fmrx", 0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl},
1730 {"fmxr", 0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg},
1731
1732 /* Memory operations. */
1733 {"flds", 0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
1734 {"fsts", 0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
1735 {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1736 {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1737 {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1738 {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1739 {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1740 {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1741 {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1742 {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1743 {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1744 {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
1745 {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1746 {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
1747 {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1748 {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
1749 {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1750 {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
1751
1752 /* Monadic operations. */
1753 {"fabss", 0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1754 {"fnegs", 0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1755 {"fsqrts", 0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1756
1757 /* Dyadic operations. */
1758 {"fadds", 0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1759 {"fsubs", 0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1760 {"fmuls", 0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1761 {"fdivs", 0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1762 {"fmacs", 0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1763 {"fmscs", 0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1764 {"fnmuls", 0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1765 {"fnmacs", 0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1766 {"fnmscs", 0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
1767
1768 /* Comparisons. */
1769 {"fcmps", 0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1770 {"fcmpzs", 0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
1771 {"fcmpes", 0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
1772 {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
1773
1774 /* VFP V1 (Double precision). */
1775 /* Moves and type conversions. */
1776 {"fcpyd", 0xeeb00b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1777 {"fcvtds", 0xeeb70ac0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
1778 {"fcvtsd", 0xeeb70bc0, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1779 {"fmdhr", 0xee200b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
1780 {"fmdlr", 0xee000b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
1781 {"fmrdh", 0xee300b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
1782 {"fmrdl", 0xee100b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
1783 {"fsitod", 0xeeb80bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
1784 {"fuitod", 0xeeb80b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
1785 {"ftosid", 0xeebd0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1786 {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1787 {"ftouid", 0xeebc0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1788 {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
1789
1790 /* Memory operations. */
1791 {"fldd", 0xed100b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
1792 {"fstd", 0xed000b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
1793 {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1794 {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1795 {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1796 {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1797 {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1798 {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
1799 {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1800 {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
1801
1802 /* Monadic operations. */
1803 {"fabsd", 0xeeb00bc0, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1804 {"fnegd", 0xeeb10b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1805 {"fsqrtd", 0xeeb10bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1806
1807 /* Dyadic operations. */
1808 {"faddd", 0xee300b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1809 {"fsubd", 0xee300b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1810 {"fmuld", 0xee200b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1811 {"fdivd", 0xee800b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1812 {"fmacd", 0xee000b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1813 {"fmscd", 0xee100b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1814 {"fnmuld", 0xee200b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1815 {"fnmacd", 0xee000b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1816 {"fnmscd", 0xee100b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
1817
1818 /* Comparisons. */
1819 {"fcmpd", 0xeeb40b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1820 {"fcmpzd", 0xeeb50b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
1821 {"fcmped", 0xeeb40bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
1822 {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
1823
1824 /* VFP V2. */
1825 {"fmsrr", 0xec400a10, 5, FPU_VFP_EXT_V2, do_vfp_sp_reg2},
1826 {"fmrrs", 0xec500a10, 5, FPU_VFP_EXT_V2, do_vfp_sp_reg2},
1827 {"fmdrr", 0xec400b10, 5, FPU_VFP_EXT_V2, do_vfp_dp_from_reg2},
1828 {"fmrrd", 0xec500b10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_dp},
1829
c9b604bd 1830 /* Intel XScale extensions to ARM V5 ISA. (All use CP0). */
63e63b07
RE
1831 {"mia", 0xee200010, 3, ARM_CEXT_XSCALE, do_xsc_mia},
1832 {"miaph", 0xee280010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1833 {"miabb", 0xee2c0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1834 {"miabt", 0xee2d0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1835 {"miatb", 0xee2e0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1836 {"miatt", 0xee2f0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
1837 {"mar", 0xec400000, 3, ARM_CEXT_XSCALE, do_xsc_mar},
1838 {"mra", 0xec500000, 3, ARM_CEXT_XSCALE, do_xsc_mra},
1839
5a6c6817
NC
1840 /* Intel Wireless MMX technology instructions. */
1841 {"tandcb", 0xee130130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
1842 {"tandch", 0xee530130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
1843 {"tandcw", 0xee930130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
1844 {"tbcstb", 0xee400010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
1845 {"tbcsth", 0xee400050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
1846 {"tbcstw", 0xee400090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
1847 {"textrcb", 0xee130170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
1848 {"textrch", 0xee530170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
1849 {"textrcw", 0xee930170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
1850 {"textrmub", 0xee100070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1851 {"textrmuh", 0xee500070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1852 {"textrmuw", 0xee900070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1853 {"textrmsb", 0xee100078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1854 {"textrmsh", 0xee500078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1855 {"textrmsw", 0xee900078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
1856 {"tinsrb", 0xee600010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
1857 {"tinsrh", 0xee600050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
1858 {"tinsrw", 0xee600090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
1859 {"tmcr", 0xee000110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmcr},
1860 {"tmcrr", 0xec400000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmcrr},
1861 {"tmia", 0xee200010, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1862 {"tmiaph", 0xee280010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1863 {"tmiabb", 0xee2c0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1864 {"tmiabt", 0xee2d0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1865 {"tmiatb", 0xee2e0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1866 {"tmiatt", 0xee2f0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
1867 {"tmovmskb", 0xee100030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
1868 {"tmovmskh", 0xee500030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
1869 {"tmovmskw", 0xee900030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
1870 {"tmrc", 0xee100110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmrc},
1871 {"tmrrc", 0xec500000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmrrc},
1872 {"torcb", 0xee130150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
1873 {"torch", 0xee530150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
1874 {"torcw", 0xee930150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
1875 {"waccb", 0xee0001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1876 {"wacch", 0xee4001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1877 {"waccw", 0xee8001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1878 {"waddbss", 0xee300180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1879 {"waddb", 0xee000180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1880 {"waddbus", 0xee100180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1881 {"waddhss", 0xee700180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1882 {"waddh", 0xee400180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1883 {"waddhus", 0xee500180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1884 {"waddwss", 0xeeb00180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1885 {"waddw", 0xee800180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1886 {"waddwus", 0xee900180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1887 {"waligni", 0xee000020, 7, ARM_CEXT_IWMMXT, do_iwmmxt_waligni},
1888 {"walignr0", 0xee800020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1889 {"walignr1", 0xee900020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1890 {"walignr2", 0xeea00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1891 {"walignr3", 0xeeb00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1892 {"wand", 0xee200000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1893 {"wandn", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1894 {"wavg2b", 0xee800000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1895 {"wavg2br", 0xee900000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1896 {"wavg2h", 0xeec00000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1897 {"wavg2hr", 0xeed00000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1898 {"wcmpeqb", 0xee000060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1899 {"wcmpeqh", 0xee400060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1900 {"wcmpeqw", 0xee800060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1901 {"wcmpgtub", 0xee100060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1902 {"wcmpgtuh", 0xee500060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1903 {"wcmpgtuw", 0xee900060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1904 {"wcmpgtsb", 0xee300060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1905 {"wcmpgtsh", 0xee700060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1906 {"wcmpgtsw", 0xeeb00060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1907 {"wldrb", 0xec100000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1908 {"wldrh", 0xec100100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1909 {"wldrw", 0xec100200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1910 {"wldrd", 0xec100300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1911 {"wmacs", 0xee600100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1912 {"wmacsz", 0xee700100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1913 {"wmacu", 0xee400100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1914 {"wmacuz", 0xee500100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1915 {"wmadds", 0xeea00100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1916 {"wmaddu", 0xee800100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1917 {"wmaxsb", 0xee200160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1918 {"wmaxsh", 0xee600160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1919 {"wmaxsw", 0xeea00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1920 {"wmaxub", 0xee000160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1921 {"wmaxuh", 0xee400160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1922 {"wmaxuw", 0xee800160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1923 {"wminsb", 0xee300160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1924 {"wminsh", 0xee700160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1925 {"wminsw", 0xeeb00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1926 {"wminub", 0xee100160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1927 {"wminuh", 0xee500160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1928 {"wminuw", 0xee900160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1929 {"wmov", 0xee000000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wmov},
1930 {"wmulsm", 0xee300100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1931 {"wmulsl", 0xee200100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1932 {"wmulum", 0xee100100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1933 {"wmulul", 0xee000100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1934 {"wor", 0xee000000, 3, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1935 {"wpackhss", 0xee700080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1936 {"wpackhus", 0xee500080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1937 {"wpackwss", 0xeeb00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1938 {"wpackwus", 0xee900080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1939 {"wpackdss", 0xeef00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1940 {"wpackdus", 0xeed00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1941 {"wrorh", 0xee700040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1942 {"wrorhg", 0xee700148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1943 {"wrorw", 0xeeb00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1944 {"wrorwg", 0xeeb00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1945 {"wrord", 0xeef00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1946 {"wrordg", 0xeef00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1947 {"wsadb", 0xee000120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1948 {"wsadbz", 0xee100120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1949 {"wsadh", 0xee400120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1950 {"wsadhz", 0xee500120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1951 {"wshufh", 0xee0001e0, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wshufh},
1952 {"wsllh", 0xee500040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1953 {"wsllhg", 0xee500148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1954 {"wsllw", 0xee900040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1955 {"wsllwg", 0xee900148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1956 {"wslld", 0xeed00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1957 {"wslldg", 0xeed00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1958 {"wsrah", 0xee400040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1959 {"wsrahg", 0xee400148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1960 {"wsraw", 0xee800040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1961 {"wsrawg", 0xee800148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1962 {"wsrad", 0xeec00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1963 {"wsradg", 0xeec00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1964 {"wsrlh", 0xee600040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1965 {"wsrlhg", 0xee600148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1966 {"wsrlw", 0xeea00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1967 {"wsrlwg", 0xeea00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1968 {"wsrld", 0xeee00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1969 {"wsrldg", 0xeee00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
1970 {"wstrb", 0xec000000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1971 {"wstrh", 0xec000100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
1972 {"wstrw", 0xec000200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1973 {"wstrd", 0xec000300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
1974 {"wsubbss", 0xee3001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1975 {"wsubb", 0xee0001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1976 {"wsubbus", 0xee1001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1977 {"wsubhss", 0xee7001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1978 {"wsubh", 0xee4001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1979 {"wsubhus", 0xee5001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1980 {"wsubwss", 0xeeb001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1981 {"wsubw", 0xee8001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1982 {"wsubwus", 0xee9001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1983 {"wunpckehub", 0xee0000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1984 {"wunpckehuh", 0xee4000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1985 {"wunpckehuw", 0xee8000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1986 {"wunpckehsb", 0xee2000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1987 {"wunpckehsh", 0xee6000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1988 {"wunpckehsw", 0xeea000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1989 {"wunpckihb", 0xee1000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1990 {"wunpckihh", 0xee5000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1991 {"wunpckihw", 0xee9000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1992 {"wunpckelub", 0xee0000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1993 {"wunpckeluh", 0xee4000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1994 {"wunpckeluw", 0xee8000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1995 {"wunpckelsb", 0xee2000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1996 {"wunpckelsh", 0xee6000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1997 {"wunpckelsw", 0xeea000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
1998 {"wunpckilb", 0xee1000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
1999 {"wunpckilh", 0xee5000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
2000 {"wunpckilw", 0xee9000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
2001 {"wxor", 0xee100000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
2002 {"wzero", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wzero},
2003
63e63b07
RE
2004 /* Cirrus Maverick instructions. */
2005 {"cfldrs", 0xec100400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
2006 {"cfldrd", 0xec500400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
2007 {"cfldr32", 0xec100500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
2008 {"cfldr64", 0xec500500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
2009 {"cfstrs", 0xec000400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
2010 {"cfstrd", 0xec400400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
2011 {"cfstr32", 0xec000500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
2012 {"cfstr64", 0xec400500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
2013 {"cfmvsr", 0xee000450, 6, ARM_CEXT_MAVERICK, do_mav_binops_2a},
2014 {"cfmvrs", 0xee100450, 6, ARM_CEXT_MAVERICK, do_mav_binops_1a},
2015 {"cfmvdlr", 0xee000410, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
2016 {"cfmvrdl", 0xee100410, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
2017 {"cfmvdhr", 0xee000430, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
2018 {"cfmvrdh", 0xee100430, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
2019 {"cfmv64lr", 0xee000510, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
2020 {"cfmvr64l", 0xee100510, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
2021 {"cfmv64hr", 0xee000530, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
2022 {"cfmvr64h", 0xee100530, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
2023 {"cfmval32", 0xee100610, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2024 {"cfmv32al", 0xee000610, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2025 {"cfmvam32", 0xee100630, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2026 {"cfmv32am", 0xee000630, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2027 {"cfmvah32", 0xee100650, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2028 {"cfmv32ah", 0xee000650, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2029 {"cfmva32", 0xee100670, 7, ARM_CEXT_MAVERICK, do_mav_binops_3a},
2030 {"cfmv32a", 0xee000670, 7, ARM_CEXT_MAVERICK, do_mav_binops_3b},
2031 {"cfmva64", 0xee100690, 7, ARM_CEXT_MAVERICK, do_mav_binops_3c},
2032 {"cfmv64a", 0xee000690, 7, ARM_CEXT_MAVERICK, do_mav_binops_3d},
2033 {"cfmvsc32", 0xee1006b0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_1},
2034 {"cfmv32sc", 0xee0006b0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_2},
2035 {"cfcpys", 0xee000400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
2036 {"cfcpyd", 0xee000420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
2037 {"cfcvtsd", 0xee000460, 7, ARM_CEXT_MAVERICK, do_mav_binops_1f},
2038 {"cfcvtds", 0xee000440, 7, ARM_CEXT_MAVERICK, do_mav_binops_1g},
2039 {"cfcvt32s", 0xee000480, 8, ARM_CEXT_MAVERICK, do_mav_binops_1h},
2040 {"cfcvt32d", 0xee0004a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1i},
2041 {"cfcvt64s", 0xee0004c0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1j},
2042 {"cfcvt64d", 0xee0004e0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1k},
2043 {"cfcvts32", 0xee100580, 8, ARM_CEXT_MAVERICK, do_mav_binops_1l},
2044 {"cfcvtd32", 0xee1005a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1m},
2045 {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l},
2046 {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m},
2047 {"cfrshl32", 0xee000550, 8, ARM_CEXT_MAVERICK, do_mav_triple_4a},
2048 {"cfrshl64", 0xee000570, 8, ARM_CEXT_MAVERICK, do_mav_triple_4b},
2049 {"cfsh32", 0xee000500, 6, ARM_CEXT_MAVERICK, do_mav_shift_1},
2050 {"cfsh64", 0xee200500, 6, ARM_CEXT_MAVERICK, do_mav_shift_2},
2051 {"cfcmps", 0xee100490, 6, ARM_CEXT_MAVERICK, do_mav_triple_5a},
2052 {"cfcmpd", 0xee1004b0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5b},
2053 {"cfcmp32", 0xee100590, 7, ARM_CEXT_MAVERICK, do_mav_triple_5c},
2054 {"cfcmp64", 0xee1005b0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5d},
2055 {"cfabss", 0xee300400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
2056 {"cfabsd", 0xee300420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
2057 {"cfnegs", 0xee300440, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
2058 {"cfnegd", 0xee300460, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
2059 {"cfadds", 0xee300480, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
2060 {"cfaddd", 0xee3004a0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
2061 {"cfsubs", 0xee3004c0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
2062 {"cfsubd", 0xee3004e0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
2063 {"cfmuls", 0xee100400, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
2064 {"cfmuld", 0xee100420, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
2065 {"cfabs32", 0xee300500, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
2066 {"cfabs64", 0xee300520, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
2067 {"cfneg32", 0xee300540, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
2068 {"cfneg64", 0xee300560, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
2069 {"cfadd32", 0xee300580, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2070 {"cfadd64", 0xee3005a0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
2071 {"cfsub32", 0xee3005c0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2072 {"cfsub64", 0xee3005e0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
2073 {"cfmul32", 0xee100500, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2074 {"cfmul64", 0xee100520, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
2075 {"cfmac32", 0xee100540, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2076 {"cfmsc32", 0xee100560, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
2077 {"cfmadd32", 0xee000600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
2078 {"cfmsub32", 0xee100600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
2079 {"cfmadda32", 0xee200600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
2080 {"cfmsuba32", 0xee300600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
b99bd4ef
NC
2081};
2082
2083/* Defines for various bits that we will want to toggle. */
2084#define INST_IMMEDIATE 0x02000000
2085#define OFFSET_REG 0x02000000
2086#define HWOFFSET_IMM 0x00400000
2087#define SHIFT_BY_REG 0x00000010
2088#define PRE_INDEX 0x01000000
2089#define INDEX_UP 0x00800000
2090#define WRITE_BACK 0x00200000
2091#define LDM_TYPE_2_OR_3 0x00400000
2092
2093#define LITERAL_MASK 0xf000f000
b99bd4ef 2094#define OPCODE_MASK 0xfe1fffff
90e4755a
RE
2095#define V4_STR_BIT 0x00000020
2096
b99bd4ef
NC
2097#define DATA_OP_SHIFT 21
2098
2099/* Codes to distinguish the arithmetic instructions. */
2100#define OPCODE_AND 0
2101#define OPCODE_EOR 1
2102#define OPCODE_SUB 2
2103#define OPCODE_RSB 3
2104#define OPCODE_ADD 4
2105#define OPCODE_ADC 5
2106#define OPCODE_SBC 6
2107#define OPCODE_RSC 7
2108#define OPCODE_TST 8
2109#define OPCODE_TEQ 9
2110#define OPCODE_CMP 10
2111#define OPCODE_CMN 11
2112#define OPCODE_ORR 12
2113#define OPCODE_MOV 13
2114#define OPCODE_BIC 14
2115#define OPCODE_MVN 15
2116
c9b604bd 2117/* Thumb v1 (ARMv4T). */
b99bd4ef
NC
2118static void do_t_nop PARAMS ((char *));
2119static void do_t_arit PARAMS ((char *));
2120static void do_t_add PARAMS ((char *));
2121static void do_t_asr PARAMS ((char *));
2122static void do_t_branch9 PARAMS ((char *));
2123static void do_t_branch12 PARAMS ((char *));
2124static void do_t_branch23 PARAMS ((char *));
2125static void do_t_bx PARAMS ((char *));
2126static void do_t_compare PARAMS ((char *));
2127static void do_t_ldmstm PARAMS ((char *));
2128static void do_t_ldr PARAMS ((char *));
2129static void do_t_ldrb PARAMS ((char *));
2130static void do_t_ldrh PARAMS ((char *));
2131static void do_t_lds PARAMS ((char *));
2132static void do_t_lsl PARAMS ((char *));
2133static void do_t_lsr PARAMS ((char *));
2134static void do_t_mov PARAMS ((char *));
2135static void do_t_push_pop PARAMS ((char *));
2136static void do_t_str PARAMS ((char *));
2137static void do_t_strb PARAMS ((char *));
2138static void do_t_strh PARAMS ((char *));
2139static void do_t_sub PARAMS ((char *));
2140static void do_t_swi PARAMS ((char *));
2141static void do_t_adr PARAMS ((char *));
2142
c9b604bd
RE
2143/* Thumb v2 (ARMv5T). */
2144static void do_t_blx PARAMS ((char *));
2145static void do_t_bkpt PARAMS ((char *));
2146
b99bd4ef
NC
2147#define T_OPCODE_MUL 0x4340
2148#define T_OPCODE_TST 0x4200
2149#define T_OPCODE_CMN 0x42c0
2150#define T_OPCODE_NEG 0x4240
2151#define T_OPCODE_MVN 0x43c0
2152
2153#define T_OPCODE_ADD_R3 0x1800
2154#define T_OPCODE_SUB_R3 0x1a00
2155#define T_OPCODE_ADD_HI 0x4400
2156#define T_OPCODE_ADD_ST 0xb000
2157#define T_OPCODE_SUB_ST 0xb080
2158#define T_OPCODE_ADD_SP 0xa800
2159#define T_OPCODE_ADD_PC 0xa000
2160#define T_OPCODE_ADD_I8 0x3000
2161#define T_OPCODE_SUB_I8 0x3800
2162#define T_OPCODE_ADD_I3 0x1c00
2163#define T_OPCODE_SUB_I3 0x1e00
2164
2165#define T_OPCODE_ASR_R 0x4100
2166#define T_OPCODE_LSL_R 0x4080
2167#define T_OPCODE_LSR_R 0x40c0
2168#define T_OPCODE_ASR_I 0x1000
2169#define T_OPCODE_LSL_I 0x0000
2170#define T_OPCODE_LSR_I 0x0800
2171
2172#define T_OPCODE_MOV_I8 0x2000
2173#define T_OPCODE_CMP_I8 0x2800
2174#define T_OPCODE_CMP_LR 0x4280
2175#define T_OPCODE_MOV_HR 0x4600
2176#define T_OPCODE_CMP_HR 0x4500
2177
2178#define T_OPCODE_LDR_PC 0x4800
2179#define T_OPCODE_LDR_SP 0x9800
2180#define T_OPCODE_STR_SP 0x9000
2181#define T_OPCODE_LDR_IW 0x6800
2182#define T_OPCODE_STR_IW 0x6000
2183#define T_OPCODE_LDR_IH 0x8800
2184#define T_OPCODE_STR_IH 0x8000
2185#define T_OPCODE_LDR_IB 0x7800
2186#define T_OPCODE_STR_IB 0x7000
2187#define T_OPCODE_LDR_RW 0x5800
2188#define T_OPCODE_STR_RW 0x5000
2189#define T_OPCODE_LDR_RH 0x5a00
2190#define T_OPCODE_STR_RH 0x5200
2191#define T_OPCODE_LDR_RB 0x5c00
2192#define T_OPCODE_STR_RB 0x5400
2193
2194#define T_OPCODE_PUSH 0xb400
2195#define T_OPCODE_POP 0xbc00
2196
2197#define T_OPCODE_BRANCH 0xe7fe
2198
2199static int thumb_reg PARAMS ((char ** str, int hi_lo));
2200
2201#define THUMB_SIZE 2 /* Size of thumb instruction. */
2202#define THUMB_REG_LO 0x1
2203#define THUMB_REG_HI 0x2
2204#define THUMB_REG_ANY 0x3
2205
2206#define THUMB_H1 0x0080
2207#define THUMB_H2 0x0040
2208
2209#define THUMB_ASR 0
2210#define THUMB_LSL 1
2211#define THUMB_LSR 2
2212
2213#define THUMB_MOVE 0
2214#define THUMB_COMPARE 1
2215
2216#define THUMB_LOAD 0
2217#define THUMB_STORE 1
2218
2219#define THUMB_PP_PC_LR 0x0100
2220
2221/* These three are used for immediate shifts, do not alter. */
2222#define THUMB_WORD 2
2223#define THUMB_HALFWORD 1
2224#define THUMB_BYTE 0
2225
2226struct thumb_opcode
2227{
2228 /* Basic string to match. */
05d2d07e 2229 const char * template;
b99bd4ef
NC
2230
2231 /* Basic instruction code. */
2232 unsigned long value;
2233
2234 int size;
2235
2236 /* Which CPU variants this exists for. */
90e4755a 2237 unsigned long variant;
b99bd4ef
NC
2238
2239 /* Function to call to parse args. */
2240 void (* parms) PARAMS ((char *));
2241};
2242
05d2d07e 2243static const struct thumb_opcode tinsns[] =
b99bd4ef 2244{
c9b604bd 2245 /* Thumb v1 (ARMv4T). */
b89dddec
RE
2246 {"adc", 0x4140, 2, ARM_EXT_V4T, do_t_arit},
2247 {"add", 0x0000, 2, ARM_EXT_V4T, do_t_add},
2248 {"and", 0x4000, 2, ARM_EXT_V4T, do_t_arit},
2249 {"asr", 0x0000, 2, ARM_EXT_V4T, do_t_asr},
2250 {"b", T_OPCODE_BRANCH, 2, ARM_EXT_V4T, do_t_branch12},
2251 {"beq", 0xd0fe, 2, ARM_EXT_V4T, do_t_branch9},
2252 {"bne", 0xd1fe, 2, ARM_EXT_V4T, do_t_branch9},
2253 {"bcs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
2254 {"bhs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
2255 {"bcc", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
2256 {"bul", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
2257 {"blo", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
2258 {"bmi", 0xd4fe, 2, ARM_EXT_V4T, do_t_branch9},
2259 {"bpl", 0xd5fe, 2, ARM_EXT_V4T, do_t_branch9},
2260 {"bvs", 0xd6fe, 2, ARM_EXT_V4T, do_t_branch9},
2261 {"bvc", 0xd7fe, 2, ARM_EXT_V4T, do_t_branch9},
2262 {"bhi", 0xd8fe, 2, ARM_EXT_V4T, do_t_branch9},
2263 {"bls", 0xd9fe, 2, ARM_EXT_V4T, do_t_branch9},
2264 {"bge", 0xdafe, 2, ARM_EXT_V4T, do_t_branch9},
2265 {"blt", 0xdbfe, 2, ARM_EXT_V4T, do_t_branch9},
2266 {"bgt", 0xdcfe, 2, ARM_EXT_V4T, do_t_branch9},
2267 {"ble", 0xddfe, 2, ARM_EXT_V4T, do_t_branch9},
2268 {"bal", 0xdefe, 2, ARM_EXT_V4T, do_t_branch9},
2269 {"bic", 0x4380, 2, ARM_EXT_V4T, do_t_arit},
2270 {"bl", 0xf7fffffe, 4, ARM_EXT_V4T, do_t_branch23},
b89dddec
RE
2271 {"bx", 0x4700, 2, ARM_EXT_V4T, do_t_bx},
2272 {"cmn", T_OPCODE_CMN, 2, ARM_EXT_V4T, do_t_arit},
2273 {"cmp", 0x0000, 2, ARM_EXT_V4T, do_t_compare},
2274 {"eor", 0x4040, 2, ARM_EXT_V4T, do_t_arit},
2275 {"ldmia", 0xc800, 2, ARM_EXT_V4T, do_t_ldmstm},
2276 {"ldr", 0x0000, 2, ARM_EXT_V4T, do_t_ldr},
2277 {"ldrb", 0x0000, 2, ARM_EXT_V4T, do_t_ldrb},
2278 {"ldrh", 0x0000, 2, ARM_EXT_V4T, do_t_ldrh},
2279 {"ldrsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
2280 {"ldrsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
2281 {"ldsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
2282 {"ldsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
2283 {"lsl", 0x0000, 2, ARM_EXT_V4T, do_t_lsl},
2284 {"lsr", 0x0000, 2, ARM_EXT_V4T, do_t_lsr},
2285 {"mov", 0x0000, 2, ARM_EXT_V4T, do_t_mov},
2286 {"mul", T_OPCODE_MUL, 2, ARM_EXT_V4T, do_t_arit},
2287 {"mvn", T_OPCODE_MVN, 2, ARM_EXT_V4T, do_t_arit},
2288 {"neg", T_OPCODE_NEG, 2, ARM_EXT_V4T, do_t_arit},
2289 {"orr", 0x4300, 2, ARM_EXT_V4T, do_t_arit},
2290 {"pop", 0xbc00, 2, ARM_EXT_V4T, do_t_push_pop},
2291 {"push", 0xb400, 2, ARM_EXT_V4T, do_t_push_pop},
2292 {"ror", 0x41c0, 2, ARM_EXT_V4T, do_t_arit},
2293 {"sbc", 0x4180, 2, ARM_EXT_V4T, do_t_arit},
2294 {"stmia", 0xc000, 2, ARM_EXT_V4T, do_t_ldmstm},
2295 {"str", 0x0000, 2, ARM_EXT_V4T, do_t_str},
2296 {"strb", 0x0000, 2, ARM_EXT_V4T, do_t_strb},
2297 {"strh", 0x0000, 2, ARM_EXT_V4T, do_t_strh},
2298 {"swi", 0xdf00, 2, ARM_EXT_V4T, do_t_swi},
2299 {"sub", 0x0000, 2, ARM_EXT_V4T, do_t_sub},
2300 {"tst", T_OPCODE_TST, 2, ARM_EXT_V4T, do_t_arit},
b99bd4ef 2301 /* Pseudo ops: */
b89dddec
RE
2302 {"adr", 0x0000, 2, ARM_EXT_V4T, do_t_adr},
2303 {"nop", 0x46C0, 2, ARM_EXT_V4T, do_t_nop}, /* mov r8,r8 */
c9b604bd
RE
2304 /* Thumb v2 (ARMv5T). */
2305 {"blx", 0, 0, ARM_EXT_V5T, do_t_blx},
2306 {"bkpt", 0xbe00, 2, ARM_EXT_V5T, do_t_bkpt},
b99bd4ef
NC
2307};
2308
f03698e6 2309#define BAD_ARGS _("bad arguments to instruction")
b99bd4ef 2310#define BAD_PC _("r15 not allowed here")
f03698e6 2311#define BAD_COND _("instruction is not conditional")
b99bd4ef
NC
2312#define ERR_NO_ACCUM _("acc0 expected")
2313
2314static struct hash_control * arm_ops_hsh = NULL;
2315static struct hash_control * arm_tops_hsh = NULL;
2316static struct hash_control * arm_cond_hsh = NULL;
2317static struct hash_control * arm_shift_hsh = NULL;
b99bd4ef
NC
2318static struct hash_control * arm_psr_hsh = NULL;
2319
2320/* This table describes all the machine specific pseudo-ops the assembler
2321 has to support. The fields are:
2322 pseudo-op name without dot
2323 function to call to execute this pseudo-op
2324 Integer arg to pass to the function. */
2325
2326static void s_req PARAMS ((int));
2327static void s_align PARAMS ((int));
2328static void s_bss PARAMS ((int));
2329static void s_even PARAMS ((int));
2330static void s_ltorg PARAMS ((int));
2331static void s_arm PARAMS ((int));
2332static void s_thumb PARAMS ((int));
2333static void s_code PARAMS ((int));
2334static void s_force_thumb PARAMS ((int));
2335static void s_thumb_func PARAMS ((int));
2336static void s_thumb_set PARAMS ((int));
76feaaf3 2337#ifdef OBJ_ELF
b99bd4ef
NC
2338static void s_arm_elf_cons PARAMS ((int));
2339#endif
2340
2341static int my_get_expression PARAMS ((expressionS *, char **));
2342
05d2d07e 2343const pseudo_typeS md_pseudo_table[] =
b99bd4ef
NC
2344{
2345 /* Never called becasue '.req' does not start line. */
2346 { "req", s_req, 0 },
2347 { "bss", s_bss, 0 },
2348 { "align", s_align, 0 },
2349 { "arm", s_arm, 0 },
2350 { "thumb", s_thumb, 0 },
2351 { "code", s_code, 0 },
2352 { "force_thumb", s_force_thumb, 0 },
2353 { "thumb_func", s_thumb_func, 0 },
2354 { "thumb_set", s_thumb_set, 0 },
2355 { "even", s_even, 0 },
2356 { "ltorg", s_ltorg, 0 },
2357 { "pool", s_ltorg, 0 },
76feaaf3 2358#ifdef OBJ_ELF
b99bd4ef
NC
2359 { "word", s_arm_elf_cons, 4 },
2360 { "long", s_arm_elf_cons, 4 },
b99bd4ef
NC
2361#else
2362 { "word", cons, 4},
2363#endif
2364 { "extend", float_cons, 'x' },
2365 { "ldouble", float_cons, 'x' },
2366 { "packed", float_cons, 'p' },
2367 { 0, 0, 0 }
2368};
2369
03b1477f
RE
2370/* Other internal functions. */
2371static int arm_parse_extension PARAMS ((char *, int *));
2372static int arm_parse_cpu PARAMS ((char *));
2373static int arm_parse_arch PARAMS ((char *));
2374static int arm_parse_fpu PARAMS ((char *));
5a6c6817
NC
2375#if defined OBJ_COFF || defined OBJ_ELF
2376static void arm_add_note PARAMS ((const char *, const char *, unsigned int));
2377#endif
03b1477f 2378
b99bd4ef
NC
2379/* Stuff needed to resolve the label ambiguity
2380 As:
2381 ...
2382 label: <insn>
2383 may differ from:
2384 ...
2385 label:
2386 <insn>
2387*/
2388
2389symbolS * last_label_seen;
b34976b6 2390static int label_is_thumb_function_name = FALSE;
b99bd4ef 2391
3d0c9500 2392/* Literal Pool stuff. */
b99bd4ef
NC
2393
2394#define MAX_LITERAL_POOL_SIZE 1024
2395
3d0c9500
NC
2396/* Literal pool structure. Held on a per-section
2397 and per-sub-section basis. */
2398typedef struct literal_pool
b99bd4ef 2399{
3d0c9500
NC
2400 expressionS literals [MAX_LITERAL_POOL_SIZE];
2401 unsigned int next_free_entry;
2402 unsigned int id;
2403 symbolS * symbol;
2404 segT section;
2405 subsegT sub_section;
61b5f74b 2406 struct literal_pool * next;
3d0c9500 2407} literal_pool;
b99bd4ef 2408
3d0c9500
NC
2409/* Pointer to a linked list of literal pools. */
2410literal_pool * list_of_pools = NULL;
b99bd4ef 2411
3d0c9500
NC
2412static literal_pool * find_literal_pool PARAMS ((void));
2413static literal_pool * find_or_make_literal_pool PARAMS ((void));
b99bd4ef 2414
3d0c9500
NC
2415static literal_pool *
2416find_literal_pool ()
2417{
2418 literal_pool * pool;
2419
2420 for (pool = list_of_pools; pool != NULL; pool = pool->next)
2421 {
2422 if (pool->section == now_seg
2423 && pool->sub_section == now_subseg)
2424 break;
2425 }
2426
2427 return pool;
2428}
b99bd4ef 2429
3d0c9500
NC
2430static literal_pool *
2431find_or_make_literal_pool ()
2432{
2433 /* Next literal pool ID number. */
2434 static unsigned int latest_pool_num = 1;
2435 literal_pool * pool;
2436
2437 pool = find_literal_pool ();
b99bd4ef 2438
3d0c9500
NC
2439 if (pool == NULL)
2440 {
2441 /* Create a new pool. */
2442 pool = (literal_pool *) xmalloc (sizeof (* pool));
2443 if (! pool)
2444 return NULL;
2445
2446 pool->next_free_entry = 0;
2447 pool->section = now_seg;
2448 pool->sub_section = now_subseg;
2449 pool->next = list_of_pools;
2450 pool->symbol = NULL;
2451
2452 /* Add it to the list. */
2453 list_of_pools = pool;
2454 }
2455
2456 /* New pools, and emptied pools, will have a NULL symbol. */
2457 if (pool->symbol == NULL)
2458 {
2459 pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
2460 (valueT) 0, &zero_address_frag);
2461 pool->id = latest_pool_num ++;
2462 }
2463
2464 /* Done. */
2465 return pool;
2466}
2467
2468/* Add the literal in the global 'inst'
2469 structure to the relevent literal pool. */
b99bd4ef
NC
2470static int
2471add_to_lit_pool ()
2472{
61b5f74b 2473 literal_pool * pool;
3d0c9500 2474 unsigned int entry;
b99bd4ef 2475
3d0c9500 2476 pool = find_or_make_literal_pool ();
b99bd4ef 2477
3d0c9500
NC
2478 /* Check if this literal value is already in the pool. */
2479 for (entry = 0; entry < pool->next_free_entry; entry ++)
b99bd4ef 2480 {
3d0c9500
NC
2481 if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2482 && (inst.reloc.exp.X_op == O_constant)
2483 && (pool->literals[entry].X_add_number
b99bd4ef 2484 == inst.reloc.exp.X_add_number)
3d0c9500
NC
2485 && (pool->literals[entry].X_unsigned
2486 == inst.reloc.exp.X_unsigned))
b99bd4ef
NC
2487 break;
2488
3d0c9500
NC
2489 if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2490 && (inst.reloc.exp.X_op == O_symbol)
2491 && (pool->literals[entry].X_add_number
b99bd4ef 2492 == inst.reloc.exp.X_add_number)
3d0c9500 2493 && (pool->literals[entry].X_add_symbol
b99bd4ef 2494 == inst.reloc.exp.X_add_symbol)
3d0c9500 2495 && (pool->literals[entry].X_op_symbol
b99bd4ef 2496 == inst.reloc.exp.X_op_symbol))
3d0c9500 2497 break;
b99bd4ef
NC
2498 }
2499
3d0c9500
NC
2500 /* Do we need to create a new entry? */
2501 if (entry == pool->next_free_entry)
b99bd4ef 2502 {
3d0c9500 2503 if (entry >= MAX_LITERAL_POOL_SIZE)
b99bd4ef 2504 {
ed71e111 2505 inst.error = _("literal pool overflow");
b99bd4ef
NC
2506 return FAIL;
2507 }
2508
3d0c9500
NC
2509 pool->literals[entry] = inst.reloc.exp;
2510 pool->next_free_entry += 1;
b99bd4ef
NC
2511 }
2512
3d0c9500 2513 inst.reloc.exp.X_op = O_symbol;
08df2379 2514 inst.reloc.exp.X_add_number = ((int) entry) * 4 - 8;
3d0c9500 2515 inst.reloc.exp.X_add_symbol = pool->symbol;
b99bd4ef
NC
2516
2517 return SUCCESS;
2518}
2519
2520/* Can't use symbol_new here, so have to create a symbol and then at
2521 a later date assign it a value. Thats what these functions do. */
2522
2523static void
2524symbol_locate (symbolP, name, segment, valu, frag)
2525 symbolS * symbolP;
05d2d07e 2526 const char * name; /* It is copied, the caller can modify. */
b99bd4ef
NC
2527 segT segment; /* Segment identifier (SEG_<something>). */
2528 valueT valu; /* Symbol value. */
2529 fragS * frag; /* Associated fragment. */
2530{
2531 unsigned int name_length;
2532 char * preserved_copy_of_name;
2533
2534 name_length = strlen (name) + 1; /* +1 for \0. */
2535 obstack_grow (&notes, name, name_length);
2536 preserved_copy_of_name = obstack_finish (&notes);
2537#ifdef STRIP_UNDERSCORE
2538 if (preserved_copy_of_name[0] == '_')
2539 preserved_copy_of_name++;
2540#endif
2541
2542#ifdef tc_canonicalize_symbol_name
2543 preserved_copy_of_name =
2544 tc_canonicalize_symbol_name (preserved_copy_of_name);
2545#endif
2546
2547 S_SET_NAME (symbolP, preserved_copy_of_name);
2548
2549 S_SET_SEGMENT (symbolP, segment);
2550 S_SET_VALUE (symbolP, valu);
c62e1cc3 2551 symbol_clear_list_pointers (symbolP);
b99bd4ef
NC
2552
2553 symbol_set_frag (symbolP, frag);
2554
2555 /* Link to end of symbol chain. */
2556 {
2557 extern int symbol_table_frozen;
2558 if (symbol_table_frozen)
2559 abort ();
2560 }
2561
2562 symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
2563
2564 obj_symbol_new_hook (symbolP);
2565
2566#ifdef tc_symbol_new_hook
2567 tc_symbol_new_hook (symbolP);
2568#endif
2569
2570#ifdef DEBUG_SYMS
2571 verify_symbol_chain (symbol_rootP, symbol_lastP);
2572#endif /* DEBUG_SYMS */
2573}
2574
2575/* Check that an immediate is valid.
2576 If so, convert it to the right format. */
2577
2578static unsigned int
2579validate_immediate (val)
2580 unsigned int val;
2581{
2582 unsigned int a;
2583 unsigned int i;
2584
2585#define rotate_left(v, n) (v << n | v >> (32 - n))
2586
2587 for (i = 0; i < 32; i += 2)
2588 if ((a = rotate_left (val, i)) <= 0xff)
2589 return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */
2590
2591 return FAIL;
2592}
2593
2594/* Check to see if an immediate can be computed as two seperate immediate
2595 values, added together. We already know that this value cannot be
2596 computed by just one ARM instruction. */
2597
2598static unsigned int
2599validate_immediate_twopart (val, highpart)
2600 unsigned int val;
2601 unsigned int * highpart;
2602{
2603 unsigned int a;
2604 unsigned int i;
2605
2606 for (i = 0; i < 32; i += 2)
2607 if (((a = rotate_left (val, i)) & 0xff) != 0)
2608 {
2609 if (a & 0xff00)
2610 {
2611 if (a & ~ 0xffff)
2612 continue;
2613 * highpart = (a >> 8) | ((i + 24) << 7);
2614 }
2615 else if (a & 0xff0000)
2616 {
2617 if (a & 0xff000000)
2618 continue;
2619 * highpart = (a >> 16) | ((i + 16) << 7);
2620 }
2621 else
2622 {
2623 assert (a & 0xff000000);
2624 * highpart = (a >> 24) | ((i + 8) << 7);
2625 }
2626
2627 return (a & 0xff) | (i << 7);
2628 }
2629
2630 return FAIL;
2631}
2632
2633static int
2634validate_offset_imm (val, hwse)
2635 unsigned int val;
2636 int hwse;
2637{
2638 if ((hwse && val > 255) || val > 4095)
2639 return FAIL;
2640 return val;
2641}
2642
2643static void
2644s_req (a)
2645 int a ATTRIBUTE_UNUSED;
2646{
f03698e6 2647 as_bad (_("invalid syntax for .req directive"));
b99bd4ef
NC
2648}
2649
2650static void
2651s_bss (ignore)
2652 int ignore ATTRIBUTE_UNUSED;
2653{
2654 /* We don't support putting frags in the BSS segment, we fake it by
2655 marking in_bss, then looking at s_skip for clues. */
2656 subseg_set (bss_section, 0);
2657 demand_empty_rest_of_line ();
2658}
2659
2660static void
2661s_even (ignore)
2662 int ignore ATTRIBUTE_UNUSED;
2663{
2664 /* Never make frag if expect extra pass. */
2665 if (!need_pass_2)
2666 frag_align (1, 0, 0);
2667
2668 record_alignment (now_seg, 1);
2669
2670 demand_empty_rest_of_line ();
2671}
2672
2673static void
2674s_ltorg (ignored)
2675 int ignored ATTRIBUTE_UNUSED;
2676{
3d0c9500
NC
2677 unsigned int entry;
2678 literal_pool * pool;
b99bd4ef
NC
2679 char sym_name[20];
2680
3d0c9500
NC
2681 pool = find_literal_pool ();
2682 if (pool == NULL
2683 || pool->symbol == NULL
2684 || pool->next_free_entry == 0)
b99bd4ef
NC
2685 return;
2686
2687 /* Align pool as you have word accesses.
2688 Only make a frag if we have to. */
2689 if (!need_pass_2)
2690 frag_align (2, 0, 0);
2691
2692 record_alignment (now_seg, 2);
2693
3d0c9500 2694 sprintf (sym_name, "$$lit_\002%x", pool->id);
b99bd4ef 2695
3d0c9500 2696 symbol_locate (pool->symbol, sym_name, now_seg,
b99bd4ef 2697 (valueT) frag_now_fix (), frag_now);
3d0c9500 2698 symbol_table_insert (pool->symbol);
b99bd4ef 2699
3d0c9500 2700 ARM_SET_THUMB (pool->symbol, thumb_mode);
b99bd4ef
NC
2701
2702#if defined OBJ_COFF || defined OBJ_ELF
3d0c9500 2703 ARM_SET_INTERWORK (pool->symbol, support_interwork);
b99bd4ef
NC
2704#endif
2705
3d0c9500 2706 for (entry = 0; entry < pool->next_free_entry; entry ++)
b99bd4ef 2707 /* First output the expression in the instruction to the pool. */
3d0c9500 2708 emit_expr (&(pool->literals[entry]), 4); /* .word */
b99bd4ef 2709
3d0c9500
NC
2710 /* Mark the pool as empty. */
2711 pool->next_free_entry = 0;
2712 pool->symbol = NULL;
b99bd4ef
NC
2713}
2714
2715/* Same as s_align_ptwo but align 0 => align 2. */
2716
2717static void
2718s_align (unused)
2719 int unused ATTRIBUTE_UNUSED;
2720{
2721 register int temp;
2722 register long temp_fill;
2723 long max_alignment = 15;
2724
2725 temp = get_absolute_expression ();
2726 if (temp > max_alignment)
f03698e6 2727 as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
b99bd4ef
NC
2728 else if (temp < 0)
2729 {
f03698e6 2730 as_bad (_("alignment negative. 0 assumed."));
b99bd4ef
NC
2731 temp = 0;
2732 }
2733
2734 if (*input_line_pointer == ',')
2735 {
2736 input_line_pointer++;
2737 temp_fill = get_absolute_expression ();
2738 }
2739 else
2740 temp_fill = 0;
2741
2742 if (!temp)
2743 temp = 2;
2744
2745 /* Only make a frag if we HAVE to. */
2746 if (temp && !need_pass_2)
2747 frag_align (temp, (int) temp_fill, 0);
2748 demand_empty_rest_of_line ();
2749
2750 record_alignment (now_seg, temp);
2751}
2752
2753static void
2754s_force_thumb (ignore)
2755 int ignore ATTRIBUTE_UNUSED;
2756{
2757 /* If we are not already in thumb mode go into it, EVEN if
2758 the target processor does not support thumb instructions.
2759 This is used by gcc/config/arm/lib1funcs.asm for example
2760 to compile interworking support functions even if the
2761 target processor should not support interworking. */
2762 if (! thumb_mode)
2763 {
2764 thumb_mode = 2;
2765
2766 record_alignment (now_seg, 1);
2767 }
2768
2769 demand_empty_rest_of_line ();
2770}
2771
2772static void
2773s_thumb_func (ignore)
2774 int ignore ATTRIBUTE_UNUSED;
2775{
2776 if (! thumb_mode)
2777 opcode_select (16);
2778
2779 /* The following label is the name/address of the start of a Thumb function.
2780 We need to know this for the interworking support. */
b34976b6 2781 label_is_thumb_function_name = TRUE;
b99bd4ef
NC
2782
2783 demand_empty_rest_of_line ();
2784}
2785
2786/* Perform a .set directive, but also mark the alias as
2787 being a thumb function. */
2788
2789static void
2790s_thumb_set (equiv)
2791 int equiv;
2792{
2793 /* XXX the following is a duplicate of the code for s_set() in read.c
2794 We cannot just call that code as we need to get at the symbol that
2795 is created. */
2796 register char * name;
2797 register char delim;
2798 register char * end_name;
2799 register symbolS * symbolP;
2800
2801 /* Especial apologies for the random logic:
2802 This just grew, and could be parsed much more simply!
2803 Dean - in haste. */
2804 name = input_line_pointer;
2805 delim = get_symbol_end ();
2806 end_name = input_line_pointer;
2807 *end_name = delim;
2808
2809 SKIP_WHITESPACE ();
2810
2811 if (*input_line_pointer != ',')
2812 {
2813 *end_name = 0;
f03698e6 2814 as_bad (_("expected comma after name \"%s\""), name);
b99bd4ef
NC
2815 *end_name = delim;
2816 ignore_rest_of_line ();
2817 return;
2818 }
2819
2820 input_line_pointer++;
2821 *end_name = 0;
2822
2823 if (name[0] == '.' && name[1] == '\0')
2824 {
2825 /* XXX - this should not happen to .thumb_set. */
2826 abort ();
2827 }
2828
2829 if ((symbolP = symbol_find (name)) == NULL
2830 && (symbolP = md_undefined_symbol (name)) == NULL)
2831 {
2832#ifndef NO_LISTING
2833 /* When doing symbol listings, play games with dummy fragments living
2834 outside the normal fragment chain to record the file and line info
2835 for this symbol. */
2836 if (listing & LISTING_SYMBOLS)
2837 {
2838 extern struct list_info_struct * listing_tail;
2839 fragS * dummy_frag = (fragS *) xmalloc (sizeof (fragS));
2840
2841 memset (dummy_frag, 0, sizeof (fragS));
2842 dummy_frag->fr_type = rs_fill;
2843 dummy_frag->line = listing_tail;
2844 symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
2845 dummy_frag->fr_symbol = symbolP;
2846 }
2847 else
2848#endif
2849 symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
2850
2851#ifdef OBJ_COFF
2852 /* "set" symbols are local unless otherwise specified. */
2853 SF_SET_LOCAL (symbolP);
2854#endif /* OBJ_COFF */
2855 } /* Make a new symbol. */
2856
2857 symbol_table_insert (symbolP);
2858
2859 * end_name = delim;
2860
2861 if (equiv
2862 && S_IS_DEFINED (symbolP)
2863 && S_GET_SEGMENT (symbolP) != reg_section)
2864 as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
2865
2866 pseudo_set (symbolP);
2867
2868 demand_empty_rest_of_line ();
2869
2870 /* XXX Now we come to the Thumb specific bit of code. */
2871
2872 THUMB_SET_FUNC (symbolP, 1);
2873 ARM_SET_THUMB (symbolP, 1);
2874#if defined OBJ_ELF || defined OBJ_COFF
2875 ARM_SET_INTERWORK (symbolP, support_interwork);
2876#endif
2877}
2878
b99bd4ef
NC
2879static void
2880opcode_select (width)
2881 int width;
2882{
2883 switch (width)
2884 {
2885 case 16:
2886 if (! thumb_mode)
2887 {
b89dddec 2888 if (! (cpu_variant & ARM_EXT_V4T))
b99bd4ef
NC
2889 as_bad (_("selected processor does not support THUMB opcodes"));
2890
2891 thumb_mode = 1;
2892 /* No need to force the alignment, since we will have been
2893 coming from ARM mode, which is word-aligned. */
2894 record_alignment (now_seg, 1);
2895 }
2896 break;
2897
2898 case 32:
2899 if (thumb_mode)
2900 {
03b1477f 2901 if ((cpu_variant & ARM_ALL) == ARM_EXT_V4T)
b99bd4ef
NC
2902 as_bad (_("selected processor does not support ARM opcodes"));
2903
2904 thumb_mode = 0;
2905
2906 if (!need_pass_2)
cc8a6dd0 2907 frag_align (2, 0, 0);
b99bd4ef 2908
cc8a6dd0 2909 record_alignment (now_seg, 1);
b99bd4ef
NC
2910 }
2911 break;
2912
2913 default:
2914 as_bad (_("invalid instruction size selected (%d)"), width);
2915 }
2916}
2917
2918static void
2919s_arm (ignore)
2920 int ignore ATTRIBUTE_UNUSED;
2921{
2922 opcode_select (32);
2923 demand_empty_rest_of_line ();
2924}
2925
2926static void
2927s_thumb (ignore)
2928 int ignore ATTRIBUTE_UNUSED;
2929{
2930 opcode_select (16);
2931 demand_empty_rest_of_line ();
2932}
2933
2934static void
2935s_code (unused)
2936 int unused ATTRIBUTE_UNUSED;
2937{
2938 register int temp;
2939
2940 temp = get_absolute_expression ();
2941 switch (temp)
2942 {
2943 case 16:
2944 case 32:
2945 opcode_select (temp);
2946 break;
2947
2948 default:
2949 as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
2950 }
2951}
2952
2953static void
2954end_of_line (str)
f03698e6 2955 char *str;
b99bd4ef
NC
2956{
2957 skip_whitespace (str);
2958
f03698e6
RE
2959 if (*str != '\0' && !inst.error)
2960 inst.error = _("garbage following instruction");
b99bd4ef
NC
2961}
2962
2963static int
2964skip_past_comma (str)
2965 char ** str;
2966{
2967 char * p = * str, c;
2968 int comma = 0;
2969
2970 while ((c = *p) == ' ' || c == ',')
2971 {
2972 p++;
2973 if (c == ',' && comma++)
2974 return FAIL;
2975 }
2976
2977 if (c == '\0')
2978 return FAIL;
2979
2980 *str = p;
2981 return comma ? SUCCESS : FAIL;
2982}
2983
2984/* A standard register must be given at this point.
2985 SHIFT is the place to put it in inst.instruction.
2986 Restores input start point on error.
2987 Returns the reg#, or FAIL. */
2988
2989static int
2990reg_required_here (str, shift)
2991 char ** str;
2992 int shift;
2993{
2994 static char buff [128]; /* XXX */
2995 int reg;
2996 char * start = * str;
2997
6c43fab6 2998 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL)
b99bd4ef
NC
2999 {
3000 if (shift >= 0)
3001 inst.instruction |= reg << shift;
3002 return reg;
3003 }
3004
3005 /* Restore the start point, we may have got a reg of the wrong class. */
3006 *str = start;
3007
3008 /* In the few cases where we might be able to accept something else
3009 this error can be overridden. */
f03698e6 3010 sprintf (buff, _("register expected, not '%.100s'"), start);
b99bd4ef
NC
3011 inst.error = buff;
3012
3013 return FAIL;
3014}
3015
5a6c6817 3016/* A Intel Wireless MMX technology register
e16bb312
NC
3017 must be given at this point.
3018 Shift is the place to put it in inst.instruction.
3019 Restores input start point on err.
3020 Returns the reg#, or FAIL. */
3021
3022static int
3023wreg_required_here (str, shift, reg_type)
3024 char ** str;
3025 int shift;
3026 enum wreg_type reg_type;
3027{
3028 static char buff [128];
3029 int reg;
3030 char * start = *str;
3031
3032 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_IWMMXT].htab)) != FAIL)
3033 {
3034 if (wr_register (reg)
3035 && (reg_type == IWMMXT_REG_WR || reg_type == IWMMXT_REG_WR_OR_WC))
3036 {
3037 if (shift >= 0)
3038 inst.instruction |= (reg ^ WR_PREFIX) << shift;
3039 return reg;
3040 }
3041 else if (wc_register (reg)
3042 && (reg_type == IWMMXT_REG_WC || reg_type == IWMMXT_REG_WR_OR_WC))
3043 {
3044 if (shift >= 0)
3045 inst.instruction |= (reg ^ WC_PREFIX) << shift;
3046 return reg;
3047 }
3048 else if ((wcg_register (reg) && reg_type == IWMMXT_REG_WCG))
3049 {
3050 if (shift >= 0)
3051 inst.instruction |= ((reg ^ WC_PREFIX) - 8) << shift;
3052 return reg;
3053 }
3054 }
3055
3056 /* Restore the start point, we may have got a reg of the wrong class. */
3057 *str = start;
3058
3059 /* In the few cases where we might be able to accept
3060 something else this error can be overridden. */
5a6c6817 3061 sprintf (buff, _("Intel Wireless MMX technology register expected, not '%.100s'"), start);
e16bb312
NC
3062 inst.error = buff;
3063
3064 return FAIL;
3065}
3066
05d2d07e 3067static const struct asm_psr *
b99bd4ef
NC
3068arm_psr_parse (ccp)
3069 register char ** ccp;
3070{
3071 char * start = * ccp;
3072 char c;
3073 char * p;
05d2d07e 3074 const struct asm_psr * psr;
b99bd4ef
NC
3075
3076 p = start;
3077
3078 /* Skip to the end of the next word in the input stream. */
3079 do
3080 {
3081 c = *p++;
3082 }
3882b010 3083 while (ISALPHA (c) || c == '_');
b99bd4ef
NC
3084
3085 /* Terminate the word. */
3086 *--p = 0;
3087
3088 /* CPSR's and SPSR's can now be lowercase. This is just a convenience
3089 feature for ease of use and backwards compatibility. */
3090 if (!strncmp (start, "cpsr", 4))
3091 strncpy (start, "CPSR", 4);
3092 else if (!strncmp (start, "spsr", 4))
3093 strncpy (start, "SPSR", 4);
3094
3095 /* Now locate the word in the psr hash table. */
05d2d07e 3096 psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start);
b99bd4ef
NC
3097
3098 /* Restore the input stream. */
3099 *p = c;
3100
3101 /* If we found a valid match, advance the
3102 stream pointer past the end of the word. */
3103 *ccp = p;
3104
3105 return psr;
3106}
3107
3108/* Parse the input looking for a PSR flag. */
3109
3110static int
3111psr_required_here (str)
3112 char ** str;
3113{
3114 char * start = * str;
05d2d07e 3115 const struct asm_psr * psr;
b99bd4ef
NC
3116
3117 psr = arm_psr_parse (str);
3118
3119 if (psr)
3120 {
3121 /* If this is the SPSR that is being modified, set the R bit. */
3122 if (! psr->cpsr)
3123 inst.instruction |= SPSR_BIT;
3124
3125 /* Set the psr flags in the MSR instruction. */
3126 inst.instruction |= psr->field << PSR_SHIFT;
3127
3128 return SUCCESS;
3129 }
3130
3131 /* In the few cases where we might be able to accept
3132 something else this error can be overridden. */
3133 inst.error = _("flag for {c}psr instruction expected");
3134
3135 /* Restore the start point. */
3136 *str = start;
3137 return FAIL;
3138}
3139
3140static int
3141co_proc_number (str)
6c43fab6 3142 char **str;
b99bd4ef
NC
3143{
3144 int processor, pchar;
6c43fab6 3145 char *start;
b99bd4ef 3146
6c43fab6
RE
3147 skip_whitespace (*str);
3148 start = *str;
b99bd4ef
NC
3149
3150 /* The data sheet seems to imply that just a number on its own is valid
3151 here, but the RISC iX assembler seems to accept a prefix 'p'. We will
3152 accept either. */
6c43fab6
RE
3153 if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab))
3154 == FAIL)
b99bd4ef 3155 {
6c43fab6
RE
3156 *str = start;
3157
3158 pchar = *(*str)++;
3159 if (pchar >= '0' && pchar <= '9')
b99bd4ef 3160 {
6c43fab6
RE
3161 processor = pchar - '0';
3162 if (**str >= '0' && **str <= '9')
b99bd4ef 3163 {
6c43fab6
RE
3164 processor = processor * 10 + *(*str)++ - '0';
3165 if (processor > 15)
3166 {
f03698e6 3167 inst.error = _("illegal co-processor number");
6c43fab6
RE
3168 return FAIL;
3169 }
b99bd4ef
NC
3170 }
3171 }
6c43fab6
RE
3172 else
3173 {
f03698e6 3174 inst.error = _("bad or missing co-processor number");
6c43fab6
RE
3175 return FAIL;
3176 }
b99bd4ef
NC
3177 }
3178
3179 inst.instruction |= processor << 8;
3180 return SUCCESS;
3181}
3182
3183static int
3184cp_opc_expr (str, where, length)
3185 char ** str;
3186 int where;
3187 int length;
3188{
3189 expressionS expr;
3190
3191 skip_whitespace (* str);
3192
3193 memset (&expr, '\0', sizeof (expr));
3194
3195 if (my_get_expression (&expr, str))
3196 return FAIL;
3197 if (expr.X_op != O_constant)
3198 {
3199 inst.error = _("bad or missing expression");
3200 return FAIL;
3201 }
3202
3203 if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
3204 {
3205 inst.error = _("immediate co-processor expression too large");
3206 return FAIL;
3207 }
3208
3209 inst.instruction |= expr.X_add_number << where;
3210 return SUCCESS;
3211}
3212
3213static int
3214cp_reg_required_here (str, where)
3215 char ** str;
3216 int where;
3217{
3218 int reg;
3219 char * start = *str;
3220
6c43fab6 3221 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
b99bd4ef 3222 {
b99bd4ef
NC
3223 inst.instruction |= reg << where;
3224 return reg;
3225 }
3226
3227 /* In the few cases where we might be able to accept something else
3228 this error can be overridden. */
f03698e6 3229 inst.error = _("co-processor register expected");
b99bd4ef
NC
3230
3231 /* Restore the start point. */
3232 *str = start;
3233 return FAIL;
3234}
3235
3236static int
3237fp_reg_required_here (str, where)
3238 char ** str;
3239 int where;
3240{
3241 int reg;
3242 char * start = * str;
3243
6c43fab6 3244 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL)
b99bd4ef 3245 {
b99bd4ef
NC
3246 inst.instruction |= reg << where;
3247 return reg;
3248 }
3249
3250 /* In the few cases where we might be able to accept something else
3251 this error can be overridden. */
f03698e6 3252 inst.error = _("floating point register expected");
b99bd4ef
NC
3253
3254 /* Restore the start point. */
3255 *str = start;
3256 return FAIL;
3257}
3258
3259static int
3260cp_address_offset (str)
3261 char ** str;
3262{
3263 int offset;
3264
3265 skip_whitespace (* str);
3266
3267 if (! is_immediate_prefix (**str))
3268 {
3269 inst.error = _("immediate expression expected");
3270 return FAIL;
3271 }
3272
3273 (*str)++;
3274
3275 if (my_get_expression (& inst.reloc.exp, str))
3276 return FAIL;
3277
3278 if (inst.reloc.exp.X_op == O_constant)
3279 {
3280 offset = inst.reloc.exp.X_add_number;
3281
3282 if (offset & 3)
3283 {
3284 inst.error = _("co-processor address must be word aligned");
3285 return FAIL;
3286 }
3287
3288 if (offset > 1023 || offset < -1023)
3289 {
3290 inst.error = _("offset too large");
3291 return FAIL;
3292 }
3293
3294 if (offset >= 0)
3295 inst.instruction |= INDEX_UP;
3296 else
3297 offset = -offset;
3298
3299 inst.instruction |= offset >> 2;
3300 }
3301 else
3302 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
3303
3304 return SUCCESS;
3305}
3306
3307static int
bfae80f2 3308cp_address_required_here (str, wb_ok)
b99bd4ef 3309 char ** str;
bfae80f2 3310 int wb_ok;
b99bd4ef
NC
3311{
3312 char * p = * str;
3313 int pre_inc = 0;
3314 int write_back = 0;
3315
3316 if (*p == '[')
3317 {
3318 int reg;
3319
3320 p++;
3321 skip_whitespace (p);
3322
3323 if ((reg = reg_required_here (& p, 16)) == FAIL)
3324 return FAIL;
3325
3326 skip_whitespace (p);
3327
3328 if (*p == ']')
3329 {
3330 p++;
3331
f02232aa
NC
3332 skip_whitespace (p);
3333
3334 if (*p == '\0')
b99bd4ef 3335 {
f02232aa
NC
3336 /* As an extension to the official ARM syntax we allow:
3337
3338 [Rn]
3339
3340 as a short hand for:
3341
3342 [Rn,#0] */
3343 inst.instruction |= PRE_INDEX | INDEX_UP;
3344 *str = p;
3345 return SUCCESS;
3346 }
3347
3348 if (skip_past_comma (& p) == FAIL)
3349 {
3350 inst.error = _("comma expected after closing square bracket");
3351 return FAIL;
3352 }
b99bd4ef 3353
f02232aa
NC
3354 skip_whitespace (p);
3355
3356 if (*p == '#')
3357 {
3358 if (wb_ok)
b99bd4ef 3359 {
f02232aa
NC
3360 /* [Rn], #expr */
3361 write_back = WRITE_BACK;
3362
3363 if (reg == REG_PC)
3364 {
3365 inst.error = _("pc may not be used in post-increment");
3366 return FAIL;
3367 }
3368
3369 if (cp_address_offset (& p) == FAIL)
3370 return FAIL;
b99bd4ef 3371 }
f02232aa
NC
3372 else
3373 pre_inc = PRE_INDEX | INDEX_UP;
3374 }
3375 else if (*p == '{')
3376 {
3377 int option;
b99bd4ef 3378
f02232aa
NC
3379 /* [Rn], {<expr>} */
3380 p++;
3381
3382 skip_whitespace (p);
3383
3384 if (my_get_expression (& inst.reloc.exp, & p))
b99bd4ef 3385 return FAIL;
f02232aa
NC
3386
3387 if (inst.reloc.exp.X_op == O_constant)
3388 {
3389 option = inst.reloc.exp.X_add_number;
3390
3391 if (option > 255 || option < 0)
3392 {
3393 inst.error = _("'option' field too large");
3394 return FAIL;
3395 }
3396
3397 skip_whitespace (p);
3398
3399 if (*p != '}')
3400 {
3401 inst.error = _("'}' expected at end of 'option' field");
3402 return FAIL;
3403 }
3404 else
3405 {
3406 p++;
3407 inst.instruction |= option;
3408 inst.instruction |= INDEX_UP;
3409 }
3410 }
3411 else
3412 {
3413 inst.error = _("non-constant expressions for 'option' field not supported");
3414 return FAIL;
3415 }
b99bd4ef
NC
3416 }
3417 else
f02232aa
NC
3418 {
3419 inst.error = _("# or { expected after comma");
3420 return FAIL;
3421 }
b99bd4ef
NC
3422 }
3423 else
3424 {
3425 /* '['Rn, #expr']'[!] */
3426
3427 if (skip_past_comma (& p) == FAIL)
3428 {
3429 inst.error = _("pre-indexed expression expected");
3430 return FAIL;
3431 }
3432
3433 pre_inc = PRE_INDEX;
3434
3435 if (cp_address_offset (& p) == FAIL)
3436 return FAIL;
3437
3438 skip_whitespace (p);
3439
3440 if (*p++ != ']')
3441 {
3442 inst.error = _("missing ]");
3443 return FAIL;
3444 }
3445
3446 skip_whitespace (p);
3447
bfae80f2 3448 if (wb_ok && *p == '!')
b99bd4ef
NC
3449 {
3450 if (reg == REG_PC)
3451 {
3452 inst.error = _("pc may not be used with write-back");
3453 return FAIL;
3454 }
3455
3456 p++;
3457 write_back = WRITE_BACK;
3458 }
3459 }
3460 }
3461 else
3462 {
3463 if (my_get_expression (&inst.reloc.exp, &p))
3464 return FAIL;
3465
3466 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
3467 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
3468 inst.reloc.pc_rel = 1;
3469 inst.instruction |= (REG_PC << 16);
3470 pre_inc = PRE_INDEX;
3471 }
3472
3473 inst.instruction |= write_back | pre_inc;
3474 *str = p;
3475 return SUCCESS;
3476}
3477
e16bb312
NC
3478static int
3479cp_byte_address_offset (str)
3480 char ** str;
3481{
3482 int offset;
3483
3484 skip_whitespace (* str);
3485
3486 if (! is_immediate_prefix (**str))
3487 {
3488 inst.error = _("immediate expression expected");
3489 return FAIL;
3490 }
3491
3492 (*str)++;
3493
3494 if (my_get_expression (& inst.reloc.exp, str))
3495 return FAIL;
3496
3497 if (inst.reloc.exp.X_op == O_constant)
3498 {
3499 offset = inst.reloc.exp.X_add_number;
3500
3501 if (offset > 255 || offset < -255)
3502 {
3503 inst.error = _("offset too large");
3504 return FAIL;
3505 }
3506
3507 if (offset >= 0)
3508 inst.instruction |= INDEX_UP;
3509 else
3510 offset = -offset;
3511
3512 inst.instruction |= offset;
3513 }
3514 else
3515 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
3516
3517 return SUCCESS;
3518}
3519
3520static int
3521cp_byte_address_required_here (str)
3522 char ** str;
3523{
3524 char * p = * str;
3525 int pre_inc = 0;
3526 int write_back = 0;
3527
3528 if (*p == '[')
3529 {
3530 int reg;
3531
3532 p++;
3533 skip_whitespace (p);
3534
3535 if ((reg = reg_required_here (& p, 16)) == FAIL)
3536 return FAIL;
3537
3538 skip_whitespace (p);
3539
3540 if (*p == ']')
3541 {
3542 p++;
3543
3544 if (skip_past_comma (& p) == SUCCESS)
3545 {
3546 /* [Rn], #expr */
3547 write_back = WRITE_BACK;
3548
3549 if (reg == REG_PC)
3550 {
3551 inst.error = _("pc may not be used in post-increment");
3552 return FAIL;
3553 }
3554
3555 if (cp_byte_address_offset (& p) == FAIL)
3556 return FAIL;
3557 }
3558 else
3559 pre_inc = PRE_INDEX | INDEX_UP;
3560 }
3561 else
3562 {
3563 /* '['Rn, #expr']'[!] */
3564
3565 if (skip_past_comma (& p) == FAIL)
3566 {
3567 inst.error = _("pre-indexed expression expected");
3568 return FAIL;
3569 }
3570
3571 pre_inc = PRE_INDEX;
3572
3573 if (cp_byte_address_offset (& p) == FAIL)
3574 return FAIL;
3575
3576 skip_whitespace (p);
3577
3578 if (*p++ != ']')
3579 {
3580 inst.error = _("missing ]");
3581 return FAIL;
3582 }
3583
3584 skip_whitespace (p);
3585
3586 if (*p == '!')
3587 {
3588 if (reg == REG_PC)
3589 {
3590 inst.error = _("pc may not be used with write-back");
3591 return FAIL;
3592 }
3593
3594 p++;
3595 write_back = WRITE_BACK;
3596 }
3597 }
3598 }
3599 else
3600 {
3601 if (my_get_expression (&inst.reloc.exp, &p))
3602 return FAIL;
3603
3604 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
3605 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
3606 inst.reloc.pc_rel = 1;
3607 inst.instruction |= (REG_PC << 16);
3608 pre_inc = PRE_INDEX;
3609 }
3610
3611 inst.instruction |= write_back | pre_inc;
3612 *str = p;
3613 return SUCCESS;
3614}
3615
b99bd4ef 3616static void
f2b7cb0a 3617do_empty (str)
b99bd4ef 3618 char * str;
b99bd4ef
NC
3619{
3620 /* Do nothing really. */
b99bd4ef
NC
3621 end_of_line (str);
3622 return;
3623}
3624
3625static void
f2b7cb0a 3626do_mrs (str)
b99bd4ef 3627 char *str;
b99bd4ef
NC
3628{
3629 int skip = 0;
3630
3631 /* Only one syntax. */
3632 skip_whitespace (str);
3633
3634 if (reg_required_here (&str, 12) == FAIL)
3635 {
3636 inst.error = BAD_ARGS;
3637 return;
3638 }
3639
3640 if (skip_past_comma (&str) == FAIL)
3641 {
3642 inst.error = _("comma expected after register name");
3643 return;
3644 }
3645
3646 skip_whitespace (str);
3647
3648 if ( strcmp (str, "CPSR") == 0
3649 || strcmp (str, "SPSR") == 0
3650 /* Lower case versions for backwards compatability. */
3651 || strcmp (str, "cpsr") == 0
3652 || strcmp (str, "spsr") == 0)
3653 skip = 4;
3654
3655 /* This is for backwards compatability with older toolchains. */
3656 else if ( strcmp (str, "cpsr_all") == 0
3657 || strcmp (str, "spsr_all") == 0)
3658 skip = 8;
3659 else
3660 {
f03698e6 3661 inst.error = _("CPSR or SPSR expected");
b99bd4ef
NC
3662 return;
3663 }
3664
3665 if (* str == 's' || * str == 'S')
3666 inst.instruction |= SPSR_BIT;
3667 str += skip;
3668
b99bd4ef
NC
3669 end_of_line (str);
3670}
3671
3672/* Two possible forms:
3673 "{C|S}PSR_<field>, Rm",
3674 "{C|S}PSR_f, #expression". */
3675
3676static void
f2b7cb0a 3677do_msr (str)
b99bd4ef 3678 char * str;
b99bd4ef
NC
3679{
3680 skip_whitespace (str);
3681
3682 if (psr_required_here (& str) == FAIL)
3683 return;
3684
3685 if (skip_past_comma (& str) == FAIL)
3686 {
3687 inst.error = _("comma missing after psr flags");
3688 return;
3689 }
3690
3691 skip_whitespace (str);
3692
3693 if (reg_required_here (& str, 0) != FAIL)
3694 {
3695 inst.error = NULL;
b99bd4ef
NC
3696 end_of_line (str);
3697 return;
3698 }
3699
3700 if (! is_immediate_prefix (* str))
3701 {
3702 inst.error =
3703 _("only a register or immediate value can follow a psr flag");
3704 return;
3705 }
3706
3707 str ++;
3708 inst.error = NULL;
3709
3710 if (my_get_expression (& inst.reloc.exp, & str))
3711 {
3712 inst.error =
3713 _("only a register or immediate value can follow a psr flag");
3714 return;
3715 }
3716
3717#if 0 /* The first edition of the ARM architecture manual stated that
3718 writing anything other than the flags with an immediate operation
3719 had UNPREDICTABLE effects. This constraint was removed in the
3720 second edition of the specification. */
3721 if ((cpu_variant & ARM_EXT_V5) != ARM_EXT_V5
3722 && inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
3723 {
3724 inst.error = _("immediate value cannot be used to set this field");
3725 return;
3726 }
3727#endif
3728
f2b7cb0a 3729 inst.instruction |= INST_IMMEDIATE;
b99bd4ef
NC
3730
3731 if (inst.reloc.exp.X_add_symbol)
3732 {
3733 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
3734 inst.reloc.pc_rel = 0;
3735 }
3736 else
3737 {
3738 unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
3739
3740 if (value == (unsigned) FAIL)
3741 {
f03698e6 3742 inst.error = _("invalid constant");
b99bd4ef
NC
3743 return;
3744 }
3745
3746 inst.instruction |= value;
3747 }
3748
3749 inst.error = NULL;
b99bd4ef
NC
3750 end_of_line (str);
3751}
3752
3753/* Long Multiply Parser
3754 UMULL RdLo, RdHi, Rm, Rs
3755 SMULL RdLo, RdHi, Rm, Rs
3756 UMLAL RdLo, RdHi, Rm, Rs
3757 SMLAL RdLo, RdHi, Rm, Rs. */
3758
3759static void
f2b7cb0a 3760do_mull (str)
b99bd4ef 3761 char * str;
b99bd4ef
NC
3762{
3763 int rdlo, rdhi, rm, rs;
3764
3765 /* Only one format "rdlo, rdhi, rm, rs". */
3766 skip_whitespace (str);
3767
3768 if ((rdlo = reg_required_here (&str, 12)) == FAIL)
3769 {
3770 inst.error = BAD_ARGS;
3771 return;
3772 }
3773
3774 if (skip_past_comma (&str) == FAIL
3775 || (rdhi = reg_required_here (&str, 16)) == FAIL)
3776 {
3777 inst.error = BAD_ARGS;
3778 return;
3779 }
3780
3781 if (skip_past_comma (&str) == FAIL
3782 || (rm = reg_required_here (&str, 0)) == FAIL)
3783 {
3784 inst.error = BAD_ARGS;
3785 return;
3786 }
3787
3788 /* rdhi, rdlo and rm must all be different. */
3789 if (rdlo == rdhi || rdlo == rm || rdhi == rm)
3790 as_tsktsk (_("rdhi, rdlo and rm must all be different"));
3791
3792 if (skip_past_comma (&str) == FAIL
3793 || (rs = reg_required_here (&str, 8)) == FAIL)
3794 {
3795 inst.error = BAD_ARGS;
3796 return;
3797 }
3798
3799 if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
3800 {
3801 inst.error = BAD_PC;
3802 return;
3803 }
3804
b99bd4ef
NC
3805 end_of_line (str);
3806 return;
3807}
3808
3809static void
f2b7cb0a 3810do_mul (str)
b99bd4ef 3811 char * str;
b99bd4ef
NC
3812{
3813 int rd, rm;
3814
3815 /* Only one format "rd, rm, rs". */
3816 skip_whitespace (str);
3817
3818 if ((rd = reg_required_here (&str, 16)) == FAIL)
3819 {
3820 inst.error = BAD_ARGS;
3821 return;
3822 }
3823
3824 if (rd == REG_PC)
3825 {
3826 inst.error = BAD_PC;
3827 return;
3828 }
3829
3830 if (skip_past_comma (&str) == FAIL
3831 || (rm = reg_required_here (&str, 0)) == FAIL)
3832 {
3833 inst.error = BAD_ARGS;
3834 return;
3835 }
3836
3837 if (rm == REG_PC)
3838 {
3839 inst.error = BAD_PC;
3840 return;
3841 }
3842
3843 if (rm == rd)
3844 as_tsktsk (_("rd and rm should be different in mul"));
3845
3846 if (skip_past_comma (&str) == FAIL
3847 || (rm = reg_required_here (&str, 8)) == FAIL)
3848 {
3849 inst.error = BAD_ARGS;
3850 return;
3851 }
3852
3853 if (rm == REG_PC)
3854 {
3855 inst.error = BAD_PC;
3856 return;
3857 }
3858
b99bd4ef
NC
3859 end_of_line (str);
3860 return;
3861}
3862
3863static void
f2b7cb0a 3864do_mla (str)
b99bd4ef 3865 char * str;
b99bd4ef
NC
3866{
3867 int rd, rm;
3868
3869 /* Only one format "rd, rm, rs, rn". */
3870 skip_whitespace (str);
3871
3872 if ((rd = reg_required_here (&str, 16)) == FAIL)
3873 {
3874 inst.error = BAD_ARGS;
3875 return;
3876 }
3877
3878 if (rd == REG_PC)
3879 {
3880 inst.error = BAD_PC;
3881 return;
3882 }
3883
3884 if (skip_past_comma (&str) == FAIL
3885 || (rm = reg_required_here (&str, 0)) == FAIL)
3886 {
3887 inst.error = BAD_ARGS;
3888 return;
3889 }
3890
3891 if (rm == REG_PC)
3892 {
3893 inst.error = BAD_PC;
3894 return;
3895 }
3896
3897 if (rm == rd)
3898 as_tsktsk (_("rd and rm should be different in mla"));
3899
3900 if (skip_past_comma (&str) == FAIL
3901 || (rd = reg_required_here (&str, 8)) == FAIL
3902 || skip_past_comma (&str) == FAIL
3903 || (rm = reg_required_here (&str, 12)) == FAIL)
3904 {
3905 inst.error = BAD_ARGS;
3906 return;
3907 }
3908
3909 if (rd == REG_PC || rm == REG_PC)
3910 {
3911 inst.error = BAD_PC;
3912 return;
3913 }
3914
b99bd4ef
NC
3915 end_of_line (str);
3916 return;
3917}
3918
3919/* Expects *str -> the characters "acc0", possibly with leading blanks.
3920 Advances *str to the next non-alphanumeric.
3921 Returns 0, or else FAIL (in which case sets inst.error).
3922
3923 (In a future XScale, there may be accumulators other than zero.
3924 At that time this routine and its callers can be upgraded to suit.) */
3925
3926static int
3927accum0_required_here (str)
3928 char ** str;
3929{
3930 static char buff [128]; /* Note the address is taken. Hence, static. */
3931 char * p = * str;
3932 char c;
3933 int result = 0; /* The accum number. */
3934
3935 skip_whitespace (p);
3936
3937 *str = p; /* Advance caller's string pointer too. */
3938 c = *p++;
3882b010 3939 while (ISALNUM (c))
b99bd4ef
NC
3940 c = *p++;
3941
3942 *--p = 0; /* Aap nul into input buffer at non-alnum. */
3943
3944 if (! ( streq (*str, "acc0") || streq (*str, "ACC0")))
3945 {
3946 sprintf (buff, _("acc0 expected, not '%.100s'"), *str);
3947 inst.error = buff;
3948 result = FAIL;
3949 }
3950
3951 *p = c; /* Unzap. */
3952 *str = p; /* Caller's string pointer to after match. */
3953 return result;
3954}
3955
3956/* Expects **str -> after a comma. May be leading blanks.
3957 Advances *str, recognizing a load mode, and setting inst.instruction.
3958 Returns rn, or else FAIL (in which case may set inst.error
3959 and not advance str)
3960
3961 Note: doesn't know Rd, so no err checks that require such knowledge. */
3962
3963static int
3964ld_mode_required_here (string)
3965 char ** string;
3966{
3967 char * str = * string;
3968 int rn;
3969 int pre_inc = 0;
3970
3971 skip_whitespace (str);
3972
3973 if (* str == '[')
3974 {
3975 str++;
3976
3977 skip_whitespace (str);
3978
3979 if ((rn = reg_required_here (& str, 16)) == FAIL)
3980 return FAIL;
3981
3982 skip_whitespace (str);
3983
3984 if (* str == ']')
3985 {
3986 str ++;
3987
3988 if (skip_past_comma (& str) == SUCCESS)
3989 {
3990 /* [Rn],... (post inc) */
90e4755a 3991 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
3992 return FAIL;
3993 }
3994 else /* [Rn] */
3995 {
cc8a6dd0 3996 skip_whitespace (str);
b99bd4ef 3997
cc8a6dd0
KH
3998 if (* str == '!')
3999 {
4000 str ++;
4001 inst.instruction |= WRITE_BACK;
4002 }
b99bd4ef
NC
4003
4004 inst.instruction |= INDEX_UP | HWOFFSET_IMM;
4005 pre_inc = 1;
4006 }
4007 }
4008 else /* [Rn,...] */
4009 {
4010 if (skip_past_comma (& str) == FAIL)
4011 {
4012 inst.error = _("pre-indexed expression expected");
4013 return FAIL;
4014 }
4015
4016 pre_inc = 1;
4017
90e4755a 4018 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
4019 return FAIL;
4020
4021 skip_whitespace (str);
4022
4023 if (* str ++ != ']')
4024 {
4025 inst.error = _("missing ]");
4026 return FAIL;
4027 }
4028
4029 skip_whitespace (str);
4030
4031 if (* str == '!')
4032 {
4033 str ++;
4034 inst.instruction |= WRITE_BACK;
4035 }
4036 }
4037 }
4038 else if (* str == '=') /* ldr's "r,=label" syntax */
4039 /* We should never reach here, because <text> = <expression> is
4040 caught gas/read.c read_a_source_file() as a .set operation. */
4041 return FAIL;
4042 else /* PC +- 8 bit immediate offset. */
4043 {
4044 if (my_get_expression (& inst.reloc.exp, & str))
4045 return FAIL;
4046
4047 inst.instruction |= HWOFFSET_IMM; /* The I bit. */
4048 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
4049 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
4050 inst.reloc.pc_rel = 1;
4051 inst.instruction |= (REG_PC << 16);
4052
4053 rn = REG_PC;
4054 pre_inc = 1;
4055 }
4056
4057 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
4058 * string = str;
4059
4060 return rn;
4061}
4062
4063/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
4064 SMLAxy{cond} Rd,Rm,Rs,Rn
4065 SMLAWy{cond} Rd,Rm,Rs,Rn
4066 Error if any register is R15. */
4067
4068static void
f2b7cb0a 4069do_smla (str)
b99bd4ef 4070 char * str;
b99bd4ef
NC
4071{
4072 int rd, rm, rs, rn;
4073
4074 skip_whitespace (str);
4075
4076 if ((rd = reg_required_here (& str, 16)) == FAIL
4077 || skip_past_comma (& str) == FAIL
4078 || (rm = reg_required_here (& str, 0)) == FAIL
4079 || skip_past_comma (& str) == FAIL
4080 || (rs = reg_required_here (& str, 8)) == FAIL
4081 || skip_past_comma (& str) == FAIL
4082 || (rn = reg_required_here (& str, 12)) == FAIL)
4083 inst.error = BAD_ARGS;
4084
4085 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC)
4086 inst.error = BAD_PC;
4087
b99bd4ef
NC
4088 else
4089 end_of_line (str);
4090}
4091
4092/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
4093 SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
4094 Error if any register is R15.
4095 Warning if Rdlo == Rdhi. */
4096
4097static void
f2b7cb0a 4098do_smlal (str)
b99bd4ef 4099 char * str;
b99bd4ef
NC
4100{
4101 int rdlo, rdhi, rm, rs;
4102
4103 skip_whitespace (str);
4104
4105 if ((rdlo = reg_required_here (& str, 12)) == FAIL
4106 || skip_past_comma (& str) == FAIL
4107 || (rdhi = reg_required_here (& str, 16)) == FAIL
4108 || skip_past_comma (& str) == FAIL
4109 || (rm = reg_required_here (& str, 0)) == FAIL
4110 || skip_past_comma (& str) == FAIL
4111 || (rs = reg_required_here (& str, 8)) == FAIL)
4112 {
4113 inst.error = BAD_ARGS;
4114 return;
4115 }
4116
4117 if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
4118 {
4119 inst.error = BAD_PC;
4120 return;
4121 }
4122
4123 if (rdlo == rdhi)
4124 as_tsktsk (_("rdhi and rdlo must be different"));
4125
f2b7cb0a 4126 end_of_line (str);
b99bd4ef
NC
4127}
4128
4129/* ARM V5E (El Segundo) signed-multiply (argument parse)
4130 SMULxy{cond} Rd,Rm,Rs
4131 Error if any register is R15. */
4132
4133static void
f2b7cb0a 4134do_smul (str)
b99bd4ef 4135 char * str;
b99bd4ef
NC
4136{
4137 int rd, rm, rs;
4138
4139 skip_whitespace (str);
4140
4141 if ((rd = reg_required_here (& str, 16)) == FAIL
4142 || skip_past_comma (& str) == FAIL
4143 || (rm = reg_required_here (& str, 0)) == FAIL
4144 || skip_past_comma (& str) == FAIL
4145 || (rs = reg_required_here (& str, 8)) == FAIL)
4146 inst.error = BAD_ARGS;
4147
4148 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC)
4149 inst.error = BAD_PC;
4150
b99bd4ef
NC
4151 else
4152 end_of_line (str);
4153}
4154
4155/* ARM V5E (El Segundo) saturating-add/subtract (argument parse)
4156 Q[D]{ADD,SUB}{cond} Rd,Rm,Rn
4157 Error if any register is R15. */
4158
4159static void
f2b7cb0a 4160do_qadd (str)
b99bd4ef 4161 char * str;
b99bd4ef
NC
4162{
4163 int rd, rm, rn;
4164
4165 skip_whitespace (str);
4166
4167 if ((rd = reg_required_here (& str, 12)) == FAIL
4168 || skip_past_comma (& str) == FAIL
4169 || (rm = reg_required_here (& str, 0)) == FAIL
4170 || skip_past_comma (& str) == FAIL
4171 || (rn = reg_required_here (& str, 16)) == FAIL)
4172 inst.error = BAD_ARGS;
4173
4174 else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
4175 inst.error = BAD_PC;
4176
b99bd4ef
NC
4177 else
4178 end_of_line (str);
4179}
4180
4181/* ARM V5E (el Segundo)
4182 MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
4183 MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
4184
4185 These are equivalent to the XScale instructions MAR and MRA,
4186 respectively, when coproc == 0, opcode == 0, and CRm == 0.
4187
4188 Result unpredicatable if Rd or Rn is R15. */
4189
4190static void
f2b7cb0a 4191do_co_reg2c (str)
b99bd4ef 4192 char * str;
b99bd4ef
NC
4193{
4194 int rd, rn;
4195
4196 skip_whitespace (str);
4197
4198 if (co_proc_number (& str) == FAIL)
4199 {
4200 if (!inst.error)
4201 inst.error = BAD_ARGS;
4202 return;
4203 }
4204
4205 if (skip_past_comma (& str) == FAIL
4206 || cp_opc_expr (& str, 4, 4) == FAIL)
4207 {
4208 if (!inst.error)
4209 inst.error = BAD_ARGS;
4210 return;
4211 }
4212
4213 if (skip_past_comma (& str) == FAIL
4214 || (rd = reg_required_here (& str, 12)) == FAIL)
4215 {
4216 if (!inst.error)
4217 inst.error = BAD_ARGS;
4218 return;
4219 }
4220
4221 if (skip_past_comma (& str) == FAIL
4222 || (rn = reg_required_here (& str, 16)) == FAIL)
4223 {
4224 if (!inst.error)
4225 inst.error = BAD_ARGS;
4226 return;
4227 }
4228
4229 /* Unpredictable result if rd or rn is R15. */
4230 if (rd == REG_PC || rn == REG_PC)
4231 as_tsktsk
f03698e6 4232 (_("Warning: instruction unpredictable when using r15"));
b99bd4ef
NC
4233
4234 if (skip_past_comma (& str) == FAIL
4235 || cp_reg_required_here (& str, 0) == FAIL)
4236 {
4237 if (!inst.error)
4238 inst.error = BAD_ARGS;
4239 return;
4240 }
4241
b99bd4ef
NC
4242 end_of_line (str);
4243}
4244
4245/* ARM V5 count-leading-zeroes instruction (argument parse)
4246 CLZ{<cond>} <Rd>, <Rm>
4247 Condition defaults to COND_ALWAYS.
4248 Error if Rd or Rm are R15. */
4249
4250static void
f2b7cb0a 4251do_clz (str)
b99bd4ef 4252 char * str;
b99bd4ef
NC
4253{
4254 int rd, rm;
4255
b99bd4ef
NC
4256 skip_whitespace (str);
4257
4258 if (((rd = reg_required_here (& str, 12)) == FAIL)
4259 || (skip_past_comma (& str) == FAIL)
4260 || ((rm = reg_required_here (& str, 0)) == FAIL))
4261 inst.error = BAD_ARGS;
4262
4263 else if (rd == REG_PC || rm == REG_PC )
4264 inst.error = BAD_PC;
4265
4266 else
4267 end_of_line (str);
4268}
4269
4270/* ARM V5 (argument parse)
4271 LDC2{L} <coproc>, <CRd>, <addressing mode>
4272 STC2{L} <coproc>, <CRd>, <addressing mode>
4273 Instruction is not conditional, and has 0xf in the codition field.
4274 Otherwise, it's the same as LDC/STC. */
4275
4276static void
f2b7cb0a 4277do_lstc2 (str)
b99bd4ef 4278 char * str;
b99bd4ef 4279{
b99bd4ef
NC
4280 skip_whitespace (str);
4281
4282 if (co_proc_number (& str) == FAIL)
4283 {
4284 if (!inst.error)
4285 inst.error = BAD_ARGS;
4286 }
4287 else if (skip_past_comma (& str) == FAIL
4288 || cp_reg_required_here (& str, 12) == FAIL)
4289 {
4290 if (!inst.error)
4291 inst.error = BAD_ARGS;
4292 }
4293 else if (skip_past_comma (& str) == FAIL
bfae80f2 4294 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
4295 {
4296 if (! inst.error)
4297 inst.error = BAD_ARGS;
4298 }
4299 else
4300 end_of_line (str);
4301}
4302
4303/* ARM V5 (argument parse)
4304 CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
4305 Instruction is not conditional, and has 0xf in the condition field.
4306 Otherwise, it's the same as CDP. */
4307
4308static void
f2b7cb0a 4309do_cdp2 (str)
b99bd4ef 4310 char * str;
b99bd4ef
NC
4311{
4312 skip_whitespace (str);
4313
4314 if (co_proc_number (& str) == FAIL)
4315 {
4316 if (!inst.error)
4317 inst.error = BAD_ARGS;
4318 return;
4319 }
4320
4321 if (skip_past_comma (& str) == FAIL
4322 || cp_opc_expr (& str, 20,4) == FAIL)
4323 {
4324 if (!inst.error)
4325 inst.error = BAD_ARGS;
4326 return;
4327 }
4328
4329 if (skip_past_comma (& str) == FAIL
4330 || cp_reg_required_here (& str, 12) == FAIL)
4331 {
4332 if (!inst.error)
4333 inst.error = BAD_ARGS;
4334 return;
4335 }
4336
4337 if (skip_past_comma (& str) == FAIL
4338 || cp_reg_required_here (& str, 16) == FAIL)
4339 {
4340 if (!inst.error)
4341 inst.error = BAD_ARGS;
4342 return;
4343 }
4344
4345 if (skip_past_comma (& str) == FAIL
4346 || cp_reg_required_here (& str, 0) == FAIL)
4347 {
4348 if (!inst.error)
4349 inst.error = BAD_ARGS;
4350 return;
4351 }
4352
4353 if (skip_past_comma (& str) == SUCCESS)
4354 {
4355 if (cp_opc_expr (& str, 5, 3) == FAIL)
4356 {
4357 if (!inst.error)
4358 inst.error = BAD_ARGS;
4359 return;
4360 }
4361 }
4362
b99bd4ef
NC
4363 end_of_line (str);
4364}
4365
4366/* ARM V5 (argument parse)
4367 MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
4368 MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
4369 Instruction is not conditional, and has 0xf in the condition field.
4370 Otherwise, it's the same as MCR/MRC. */
4371
4372static void
f2b7cb0a 4373do_co_reg2 (str)
b99bd4ef 4374 char * str;
b99bd4ef
NC
4375{
4376 skip_whitespace (str);
4377
4378 if (co_proc_number (& str) == FAIL)
4379 {
4380 if (!inst.error)
4381 inst.error = BAD_ARGS;
4382 return;
4383 }
4384
4385 if (skip_past_comma (& str) == FAIL
4386 || cp_opc_expr (& str, 21, 3) == FAIL)
4387 {
4388 if (!inst.error)
4389 inst.error = BAD_ARGS;
4390 return;
4391 }
4392
4393 if (skip_past_comma (& str) == FAIL
4394 || reg_required_here (& str, 12) == FAIL)
4395 {
4396 if (!inst.error)
4397 inst.error = BAD_ARGS;
4398 return;
4399 }
4400
4401 if (skip_past_comma (& str) == FAIL
4402 || cp_reg_required_here (& str, 16) == FAIL)
4403 {
4404 if (!inst.error)
4405 inst.error = BAD_ARGS;
4406 return;
4407 }
4408
4409 if (skip_past_comma (& str) == FAIL
4410 || cp_reg_required_here (& str, 0) == FAIL)
4411 {
4412 if (!inst.error)
4413 inst.error = BAD_ARGS;
4414 return;
4415 }
4416
4417 if (skip_past_comma (& str) == SUCCESS)
4418 {
4419 if (cp_opc_expr (& str, 5, 3) == FAIL)
4420 {
4421 if (!inst.error)
4422 inst.error = BAD_ARGS;
4423 return;
4424 }
4425 }
4426
b99bd4ef
NC
4427 end_of_line (str);
4428}
4429
ea6ef066
RE
4430/* ARM v5TEJ. Jump to Jazelle code. */
4431static void
4432do_bxj (str)
4433 char * str;
4434{
4435 int reg;
4436
4437 skip_whitespace (str);
4438
4439 if ((reg = reg_required_here (&str, 0)) == FAIL)
4440 {
4441 inst.error = BAD_ARGS;
4442 return;
4443 }
4444
4445 /* Note - it is not illegal to do a "bxj pc". Useless, but not illegal. */
4446 if (reg == REG_PC)
4447 as_tsktsk (_("use of r15 in bxj is not really useful"));
4448
4449 end_of_line (str);
4450}
4451
b99bd4ef
NC
4452/* THUMB V5 breakpoint instruction (argument parse)
4453 BKPT <immed_8>. */
4454
4455static void
4456do_t_bkpt (str)
4457 char * str;
4458{
4459 expressionS expr;
4460 unsigned long number;
4461
4462 skip_whitespace (str);
4463
4464 /* Allow optional leading '#'. */
4465 if (is_immediate_prefix (*str))
4466 str ++;
4467
4468 memset (& expr, '\0', sizeof (expr));
143c8e19
NC
4469 if (my_get_expression (& expr, & str)
4470 || (expr.X_op != O_constant
4471 /* As a convenience we allow 'bkpt' without an operand. */
4472 && expr.X_op != O_absent))
b99bd4ef 4473 {
143c8e19 4474 inst.error = _("bad expression");
b99bd4ef
NC
4475 return;
4476 }
4477
4478 number = expr.X_add_number;
4479
4480 /* Check it fits an 8 bit unsigned. */
4481 if (number != (number & 0xff))
4482 {
4483 inst.error = _("immediate value out of range");
4484 return;
4485 }
4486
4487 inst.instruction |= number;
4488
4489 end_of_line (str);
4490}
4491
4492/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
4493 Expects inst.instruction is set for BLX(1).
4494 Note: this is cloned from do_branch, and the reloc changed to be a
4495 new one that can cope with setting one extra bit (the H bit). */
4496
4497static void
f2b7cb0a 4498do_branch25 (str)
b99bd4ef 4499 char * str;
b99bd4ef
NC
4500{
4501 if (my_get_expression (& inst.reloc.exp, & str))
4502 return;
4503
4504#ifdef OBJ_ELF
4505 {
4506 char * save_in;
4507
4508 /* ScottB: February 5, 1998 */
4509 /* Check to see of PLT32 reloc required for the instruction. */
4510
4511 /* arm_parse_reloc() works on input_line_pointer.
4512 We actually want to parse the operands to the branch instruction
4513 passed in 'str'. Save the input pointer and restore it later. */
4514 save_in = input_line_pointer;
4515 input_line_pointer = str;
4516
4517 if (inst.reloc.exp.X_op == O_symbol
4518 && *str == '('
4519 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
4520 {
4521 inst.reloc.type = BFD_RELOC_ARM_PLT32;
4522 inst.reloc.pc_rel = 0;
4523 /* Modify str to point to after parsed operands, otherwise
4524 end_of_line() will complain about the (PLT) left in str. */
4525 str = input_line_pointer;
4526 }
4527 else
4528 {
4529 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4530 inst.reloc.pc_rel = 1;
4531 }
4532
4533 input_line_pointer = save_in;
4534 }
4535#else
4536 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4537 inst.reloc.pc_rel = 1;
4538#endif /* OBJ_ELF */
4539
4540 end_of_line (str);
4541}
4542
4543/* ARM V5 branch-link-exchange instruction (argument parse)
4544 BLX <target_addr> ie BLX(1)
4545 BLX{<condition>} <Rm> ie BLX(2)
4546 Unfortunately, there are two different opcodes for this mnemonic.
4547 So, the insns[].value is not used, and the code here zaps values
4548 into inst.instruction.
4549 Also, the <target_addr> can be 25 bits, hence has its own reloc. */
4550
4551static void
f2b7cb0a 4552do_blx (str)
b99bd4ef 4553 char * str;
b99bd4ef
NC
4554{
4555 char * mystr = str;
4556 int rm;
4557
b99bd4ef
NC
4558 skip_whitespace (mystr);
4559 rm = reg_required_here (& mystr, 0);
4560
4561 /* The above may set inst.error. Ignore his opinion. */
4562 inst.error = 0;
4563
4564 if (rm != FAIL)
4565 {
4566 /* Arg is a register.
4567 Use the condition code our caller put in inst.instruction.
4568 Pass ourselves off as a BX with a funny opcode. */
4569 inst.instruction |= 0x012fff30;
f2b7cb0a 4570 do_bx (str);
b99bd4ef
NC
4571 }
4572 else
4573 {
4574 /* This must be is BLX <target address>, no condition allowed. */
4575 if (inst.instruction != COND_ALWAYS)
cc8a6dd0
KH
4576 {
4577 inst.error = BAD_COND;
b99bd4ef 4578 return;
cc8a6dd0 4579 }
b99bd4ef
NC
4580
4581 inst.instruction = 0xfafffffe;
4582
4583 /* Process like a B/BL, but with a different reloc.
4584 Note that B/BL expecte fffffe, not 0, offset in the opcode table. */
f2b7cb0a 4585 do_branch25 (str);
b99bd4ef
NC
4586 }
4587}
4588
4589/* ARM V5 Thumb BLX (argument parse)
4590 BLX <target_addr> which is BLX(1)
4591 BLX <Rm> which is BLX(2)
4592 Unfortunately, there are two different opcodes for this mnemonic.
4593 So, the tinsns[].value is not used, and the code here zaps values
4594 into inst.instruction. */
4595
4596static void
4597do_t_blx (str)
4598 char * str;
4599{
4600 char * mystr = str;
4601 int rm;
4602
4603 skip_whitespace (mystr);
4604 inst.instruction = 0x4780;
4605
4606 /* Note that this call is to the ARM register recognizer. BLX(2)
4607 uses the ARM register space, not the Thumb one, so a call to
4608 thumb_reg() would be wrong. */
4609 rm = reg_required_here (& mystr, 3);
4610 inst.error = 0;
4611
4612 if (rm != FAIL)
4613 {
4614 /* It's BLX(2). The .instruction was zapped with rm & is final. */
4615 inst.size = 2;
4616 }
4617 else
4618 {
4619 /* No ARM register. This must be BLX(1). Change the .instruction. */
4620 inst.instruction = 0xf7ffeffe;
4621 inst.size = 4;
4622
4623 if (my_get_expression (& inst.reloc.exp, & mystr))
4624 return;
4625
4626 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
4627 inst.reloc.pc_rel = 1;
4628 }
4629
4630 end_of_line (mystr);
4631}
4632
4633/* ARM V5 breakpoint instruction (argument parse)
4634 BKPT <16 bit unsigned immediate>
4635 Instruction is not conditional.
4636 The bit pattern given in insns[] has the COND_ALWAYS condition,
cc8a6dd0 4637 and it is an error if the caller tried to override that. */
b99bd4ef
NC
4638
4639static void
f2b7cb0a 4640do_bkpt (str)
b99bd4ef 4641 char * str;
b99bd4ef
NC
4642{
4643 expressionS expr;
4644 unsigned long number;
4645
4646 skip_whitespace (str);
4647
4648 /* Allow optional leading '#'. */
4649 if (is_immediate_prefix (* str))
4650 str++;
4651
4652 memset (& expr, '\0', sizeof (expr));
4653
143c8e19
NC
4654 if (my_get_expression (& expr, & str)
4655 || (expr.X_op != O_constant
4656 /* As a convenience we allow 'bkpt' without an operand. */
4657 && expr.X_op != O_absent))
b99bd4ef 4658 {
143c8e19 4659 inst.error = _("bad expression");
b99bd4ef
NC
4660 return;
4661 }
4662
4663 number = expr.X_add_number;
4664
4665 /* Check it fits a 16 bit unsigned. */
4666 if (number != (number & 0xffff))
4667 {
4668 inst.error = _("immediate value out of range");
4669 return;
4670 }
4671
4672 /* Top 12 of 16 bits to bits 19:8. */
4673 inst.instruction |= (number & 0xfff0) << 4;
4674
4675 /* Bottom 4 of 16 bits to bits 3:0. */
4676 inst.instruction |= number & 0xf;
4677
4678 end_of_line (str);
b99bd4ef
NC
4679}
4680
e16bb312
NC
4681static unsigned long check_iwmmxt_insn PARAMS ((char *, enum iwmmxt_insn_type, int));
4682
4683/* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate. */
4684
4685static unsigned long
4686check_iwmmxt_insn (str, insn_type, immediate_size)
4687 char * str;
4688 enum iwmmxt_insn_type insn_type;
4689 int immediate_size;
4690{
4691 int reg = 0;
4692 const char * inst_error;
4693 expressionS expr;
4694 unsigned long number;
4695
4696 inst_error = inst.error;
4697 if (!inst.error)
4698 inst.error = BAD_ARGS;
4699 skip_whitespace (str);
4700
4701 switch (insn_type)
4702 {
4703 case check_rd:
4704 if ((reg = reg_required_here (&str, 12)) == FAIL)
4705 return FAIL;
4706 break;
4707
4708 case check_wr:
4709 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR)) == FAIL)
4710 return FAIL;
4711 break;
4712
4713 case check_wrwr:
4714 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4715 || skip_past_comma (&str) == FAIL
4716 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
4717 return FAIL;
4718 break;
4719
4720 case check_wrwrwr:
4721 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4722 || skip_past_comma (&str) == FAIL
4723 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4724 || skip_past_comma (&str) == FAIL
4725 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
4726 return FAIL;
4727 break;
4728
4729 case check_wrwrwcg:
4730 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4731 || skip_past_comma (&str) == FAIL
4732 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4733 || skip_past_comma (&str) == FAIL
4734 || wreg_required_here (&str, 0, IWMMXT_REG_WCG) == FAIL))
4735 return FAIL;
4736 break;
4737
4738 case check_tbcst:
4739 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4740 || skip_past_comma (&str) == FAIL
4741 || reg_required_here (&str, 12) == FAIL))
4742 return FAIL;
4743 break;
4744
4745 case check_tmovmsk:
4746 if ((reg_required_here (&str, 12) == FAIL
4747 || skip_past_comma (&str) == FAIL
4748 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
4749 return FAIL;
4750 break;
4751
4752 case check_tmia:
4753 if ((wreg_required_here (&str, 5, IWMMXT_REG_WR) == FAIL
4754 || skip_past_comma (&str) == FAIL
4755 || reg_required_here (&str, 0) == FAIL
4756 || skip_past_comma (&str) == FAIL
4757 || reg_required_here (&str, 12) == FAIL))
4758 return FAIL;
4759 break;
4760
4761 case check_tmcrr:
4762 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
4763 || skip_past_comma (&str) == FAIL
4764 || reg_required_here (&str, 12) == FAIL
4765 || skip_past_comma (&str) == FAIL
4766 || reg_required_here (&str, 16) == FAIL))
4767 return FAIL;
4768 break;
4769
4770 case check_tmrrc:
4771 if ((reg_required_here (&str, 12) == FAIL
4772 || skip_past_comma (&str) == FAIL
4773 || reg_required_here (&str, 16) == FAIL
4774 || skip_past_comma (&str) == FAIL
4775 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
4776 return FAIL;
4777 break;
4778
4779 case check_tmcr:
4780 if ((wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL
4781 || skip_past_comma (&str) == FAIL
4782 || reg_required_here (&str, 12) == FAIL))
4783 return FAIL;
4784 break;
4785
4786 case check_tmrc:
4787 if ((reg_required_here (&str, 12) == FAIL
4788 || skip_past_comma (&str) == FAIL
4789 || wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL))
4790 return FAIL;
4791 break;
4792
4793 case check_tinsr:
4794 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4795 || skip_past_comma (&str) == FAIL
4796 || reg_required_here (&str, 12) == FAIL
4797 || skip_past_comma (&str) == FAIL))
4798 return FAIL;
4799 break;
4800
4801 case check_textrc:
4802 if ((reg_required_here (&str, 12) == FAIL
4803 || skip_past_comma (&str) == FAIL))
4804 return FAIL;
4805 break;
4806
4807 case check_waligni:
4808 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4809 || skip_past_comma (&str) == FAIL
4810 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4811 || skip_past_comma (&str) == FAIL
4812 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
4813 || skip_past_comma (&str) == FAIL))
4814 return FAIL;
4815 break;
4816
4817 case check_textrm:
4818 if ((reg_required_here (&str, 12) == FAIL
4819 || skip_past_comma (&str) == FAIL
4820 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4821 || skip_past_comma (&str) == FAIL))
4822 return FAIL;
4823 break;
4824
4825 case check_wshufh:
4826 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
4827 || skip_past_comma (&str) == FAIL
4828 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
4829 || skip_past_comma (&str) == FAIL))
4830 return FAIL;
4831 break;
4832 }
4833
4834 if (immediate_size == 0)
4835 {
4836 end_of_line (str);
4837 inst.error = inst_error;
4838 return reg;
4839 }
4840 else
4841 {
4842 skip_whitespace (str);
4843
4844 /* Allow optional leading '#'. */
4845 if (is_immediate_prefix (* str))
4846 str++;
4847
4848 memset (& expr, '\0', sizeof (expr));
4849
4850 if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
4851 {
4852 inst.error = _("bad or missing expression");
4853 return FAIL;
4854 }
4855
4856 number = expr.X_add_number;
4857
4858 if (number != (number & immediate_size))
4859 {
4860 inst.error = _("immediate value out of range");
4861 return FAIL;
4862 }
4863 end_of_line (str);
4864 inst.error = inst_error;
4865 return number;
4866 }
4867}
4868
4869static void
4870do_iwmmxt_byte_addr (str)
4871 char * str;
4872{
4873 int op = (inst.instruction & 0x300) >> 8;
4874 int reg;
4875
4876 inst.instruction &= ~0x300;
4877 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
4878
4879 skip_whitespace (str);
4880
4881 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
4882 || skip_past_comma (& str) == FAIL
4883 || cp_byte_address_required_here (&str) == FAIL)
4884 {
4885 if (! inst.error)
4886 inst.error = BAD_ARGS;
4887 }
4888 else
4889 end_of_line (str);
4890
4891 if (wc_register (reg))
4892 {
ece01a63 4893 as_bad (_("non-word size not supported with control register"));
e16bb312
NC
4894 inst.instruction |= 0xf0000100;
4895 inst.instruction &= ~0x00400000;
4896 }
4897}
4898
4899static void
4900do_iwmmxt_tandc (str)
4901 char * str;
4902{
4903 int reg;
4904
4905 reg = check_iwmmxt_insn (str, check_rd, 0);
4906
4907 if (reg != REG_PC && !inst.error)
4908 inst.error = _("only r15 allowed here");
4909 return;
4910}
4911
4912static void
4913do_iwmmxt_tbcst (str)
4914 char * str;
4915{
4916 check_iwmmxt_insn (str, check_tbcst, 0);
4917
4918 return;
4919}
4920
4921static void
4922do_iwmmxt_textrc (str)
4923 char * str;
4924{
4925 unsigned long number;
4926
4927 if ((number = check_iwmmxt_insn (str, check_textrc, 7)) == (unsigned long) FAIL)
4928 return;
4929
4930 inst.instruction |= number & 0x7;
4931 return;
4932}
4933
4934static void
4935do_iwmmxt_textrm (str)
4936 char * str;
4937{
4938 unsigned long number;
4939
4940 if ((number = check_iwmmxt_insn (str, check_textrm, 7)) == (unsigned long) FAIL)
4941 return;
4942
4943 inst.instruction |= number & 0x7;
4944}
4945
4946static void
4947do_iwmmxt_tinsr (str)
4948 char * str;
4949{
4950 unsigned long number;
4951
4952 if ((number = check_iwmmxt_insn (str, check_tinsr, 7)) == (unsigned long) FAIL)
4953 return;
4954
4955 inst.instruction |= number & 0x7;
4956 return;
4957}
4958
4959static void
4960do_iwmmxt_tmcr (str)
4961 char * str;
4962{
4963 check_iwmmxt_insn (str, check_tmcr, 0);
4964
4965 return;
4966}
4967
4968static void
4969do_iwmmxt_tmcrr (str)
4970 char * str;
4971{
4972 check_iwmmxt_insn (str, check_tmcrr, 0);
4973
4974 return;
4975}
4976
4977static void
4978do_iwmmxt_tmia (str)
4979 char * str;
4980{
4981 check_iwmmxt_insn (str, check_tmia, 0);
4982
4983 return;
4984}
4985
4986static void
4987do_iwmmxt_tmovmsk (str)
4988 char * str;
4989{
4990 check_iwmmxt_insn (str, check_tmovmsk, 0);
4991
4992 return;
4993}
4994
4995static void
4996do_iwmmxt_tmrc (str)
4997 char * str;
4998{
4999 check_iwmmxt_insn (str, check_tmrc, 0);
5000
5001 return;
5002}
5003
5004static void
5005do_iwmmxt_tmrrc (str)
5006 char * str;
5007{
5008 check_iwmmxt_insn (str, check_tmrrc, 0);
5009
5010 return;
5011}
5012
5013static void
5014do_iwmmxt_torc (str)
5015 char * str;
5016{
5017 check_iwmmxt_insn (str, check_rd, 0);
5018 return;
5019}
5020
5021static void
5022do_iwmmxt_waligni (str)
5023 char * str;
5024{
5025 unsigned long number;
5026
5027 if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL)
5028 return;
5029
5030 inst.instruction |= ((number & 0x7) << 20);
5031 return;
5032}
5033
5034static void
5035do_iwmmxt_wmov (str)
5036 char * str;
5037{
5038 if (check_iwmmxt_insn (str, check_wrwr, 0) == (unsigned long) FAIL)
5039 return;
5040
5041 inst.instruction |= ((inst.instruction >> 16) & 0xf);
5042 return;
5043}
5044
5045static void
5046do_iwmmxt_word_addr (str)
5047 char * str;
5048{
5049 int op = (inst.instruction & 0x300) >> 8;
5050 int reg;
5051
5052 inst.instruction &= ~0x300;
5053 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
5054
5055 skip_whitespace (str);
5056
5057 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
5058 || skip_past_comma (& str) == FAIL
5059 || cp_address_required_here (& str, CP_WB_OK) == FAIL)
5060 {
5061 if (! inst.error)
5062 inst.error = BAD_ARGS;
5063 }
5064 else
5065 end_of_line (str);
5066
5067 if (wc_register (reg))
5068 {
ece01a63
ILT
5069 if ((inst.instruction & COND_MASK) != COND_ALWAYS)
5070 as_bad (_("conditional execution not supported with control register"));
5071 if (op != 2)
5072 as_bad (_("non-word size not supported with control register"));
e16bb312
NC
5073 inst.instruction |= 0xf0000100;
5074 inst.instruction &= ~0x00400000;
5075 }
5076}
5077
5078static void
5079do_iwmmxt_wrwr (str)
5080 char * str;
5081{
5082 check_iwmmxt_insn (str, check_wrwr, 0);
5083
5084 return;
5085}
5086
5087static void
5088do_iwmmxt_wrwrwcg (str)
5089 char * str;
5090{
5091 check_iwmmxt_insn (str, check_wrwrwcg, 0);
5092
5093 return;
5094}
5095
5096static void
5097do_iwmmxt_wrwrwr (str)
5098 char * str;
5099{
5100 check_iwmmxt_insn (str, check_wrwrwr, 0);
5101
5102 return;
5103}
5104
5105static void
5106do_iwmmxt_wshufh (str)
5107 char * str;
5108{
5109 unsigned long number;
5110
5111 if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL)
5112 return;
5113
5114 inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf);
5115 return;
5116}
5117
5118static void
5119do_iwmmxt_wzero (str)
5120 char * str;
5121{
5122 if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL)
5123 return;
5124
5125 inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16);
5126 return;
5127}
5128
b99bd4ef
NC
5129/* Xscale multiply-accumulate (argument parse)
5130 MIAcc acc0,Rm,Rs
5131 MIAPHcc acc0,Rm,Rs
5132 MIAxycc acc0,Rm,Rs. */
5133
5134static void
63e63b07 5135do_xsc_mia (str)
b99bd4ef 5136 char * str;
b99bd4ef
NC
5137{
5138 int rs;
5139 int rm;
5140
f2b7cb0a 5141 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5142 inst.error = ERR_NO_ACCUM;
5143
5144 else if (skip_past_comma (& str) == FAIL
5145 || (rm = reg_required_here (& str, 0)) == FAIL)
5146 inst.error = BAD_ARGS;
5147
5148 else if (skip_past_comma (& str) == FAIL
5149 || (rs = reg_required_here (& str, 12)) == FAIL)
5150 inst.error = BAD_ARGS;
5151
5152 /* inst.instruction has now been zapped with both rm and rs. */
5153 else if (rm == REG_PC || rs == REG_PC)
5154 inst.error = BAD_PC; /* Undefined result if rm or rs is R15. */
5155
5156 else
5157 end_of_line (str);
5158}
5159
5160/* Xscale move-accumulator-register (argument parse)
5161
5162 MARcc acc0,RdLo,RdHi. */
5163
5164static void
63e63b07 5165do_xsc_mar (str)
b99bd4ef 5166 char * str;
b99bd4ef
NC
5167{
5168 int rdlo, rdhi;
5169
f2b7cb0a 5170 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5171 inst.error = ERR_NO_ACCUM;
5172
5173 else if (skip_past_comma (& str) == FAIL
5174 || (rdlo = reg_required_here (& str, 12)) == FAIL)
5175 inst.error = BAD_ARGS;
5176
5177 else if (skip_past_comma (& str) == FAIL
5178 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5179 inst.error = BAD_ARGS;
5180
5181 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5182 else if (rdlo == REG_PC || rdhi == REG_PC)
5183 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5184
5185 else
5186 end_of_line (str);
5187}
5188
5189/* Xscale move-register-accumulator (argument parse)
5190
5191 MRAcc RdLo,RdHi,acc0. */
5192
5193static void
63e63b07 5194do_xsc_mra (str)
b99bd4ef 5195 char * str;
b99bd4ef
NC
5196{
5197 int rdlo;
5198 int rdhi;
5199
b99bd4ef
NC
5200 skip_whitespace (str);
5201
5202 if ((rdlo = reg_required_here (& str, 12)) == FAIL)
5203 inst.error = BAD_ARGS;
5204
5205 else if (skip_past_comma (& str) == FAIL
5206 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5207 inst.error = BAD_ARGS;
5208
5209 else if (skip_past_comma (& str) == FAIL
5210 || accum0_required_here (& str) == FAIL)
5211 inst.error = ERR_NO_ACCUM;
5212
5213 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5214 else if (rdlo == rdhi)
5215 inst.error = BAD_ARGS; /* Undefined result if 2 writes to same reg. */
5216
5217 else if (rdlo == REG_PC || rdhi == REG_PC)
5218 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5219 else
5220 end_of_line (str);
5221}
5222
c9b604bd 5223/* ARMv5TE: Preload-Cache
b99bd4ef
NC
5224
5225 PLD <addr_mode>
5226
5227 Syntactically, like LDR with B=1, W=0, L=1. */
5228
5229static void
f2b7cb0a 5230do_pld (str)
b99bd4ef 5231 char * str;
b99bd4ef
NC
5232{
5233 int rd;
5234
b99bd4ef
NC
5235 skip_whitespace (str);
5236
5237 if (* str != '[')
5238 {
5239 inst.error = _("'[' expected after PLD mnemonic");
5240 return;
5241 }
5242
90e4755a 5243 ++str;
b99bd4ef
NC
5244 skip_whitespace (str);
5245
5246 if ((rd = reg_required_here (& str, 16)) == FAIL)
5247 return;
5248
5249 skip_whitespace (str);
5250
90e4755a 5251 if (*str == ']')
b99bd4ef
NC
5252 {
5253 /* [Rn], ... ? */
90e4755a 5254 ++str;
b99bd4ef
NC
5255 skip_whitespace (str);
5256
90e4755a
RE
5257 /* Post-indexed addressing is not allowed with PLD. */
5258 if (skip_past_comma (&str) == SUCCESS)
b99bd4ef 5259 {
90e4755a
RE
5260 inst.error
5261 = _("post-indexed expression used in preload instruction");
5262 return;
b99bd4ef 5263 }
90e4755a 5264 else if (*str == '!') /* [Rn]! */
b99bd4ef
NC
5265 {
5266 inst.error = _("writeback used in preload instruction");
90e4755a 5267 ++str;
b99bd4ef
NC
5268 }
5269 else /* [Rn] */
5270 inst.instruction |= INDEX_UP | PRE_INDEX;
5271 }
5272 else /* [Rn, ...] */
5273 {
5274 if (skip_past_comma (& str) == FAIL)
5275 {
5276 inst.error = _("pre-indexed expression expected");
5277 return;
5278 }
5279
90e4755a 5280 if (ldst_extend (&str) == FAIL)
b99bd4ef
NC
5281 return;
5282
5283 skip_whitespace (str);
5284
5285 if (* str != ']')
5286 {
5287 inst.error = _("missing ]");
5288 return;
5289 }
5290
5291 ++ str;
5292 skip_whitespace (str);
5293
5294 if (* str == '!') /* [Rn]! */
5295 {
5296 inst.error = _("writeback used in preload instruction");
5297 ++ str;
5298 }
5299
5300 inst.instruction |= PRE_INDEX;
5301 }
5302
5303 end_of_line (str);
5304}
5305
c9b604bd 5306/* ARMv5TE load-consecutive (argument parse)
b99bd4ef
NC
5307 Mode is like LDRH.
5308
5309 LDRccD R, mode
5310 STRccD R, mode. */
5311
5312static void
f2b7cb0a 5313do_ldrd (str)
b99bd4ef 5314 char * str;
b99bd4ef
NC
5315{
5316 int rd;
5317 int rn;
5318
b99bd4ef
NC
5319 skip_whitespace (str);
5320
5321 if ((rd = reg_required_here (& str, 12)) == FAIL)
5322 {
5323 inst.error = BAD_ARGS;
5324 return;
5325 }
5326
5327 if (skip_past_comma (& str) == FAIL
5328 || (rn = ld_mode_required_here (& str)) == FAIL)
5329 {
5330 if (!inst.error)
cc8a6dd0 5331 inst.error = BAD_ARGS;
b99bd4ef
NC
5332 return;
5333 }
5334
5335 /* inst.instruction has now been zapped with Rd and the addressing mode. */
5336 if (rd & 1) /* Unpredictable result if Rd is odd. */
5337 {
f03698e6 5338 inst.error = _("destination register must be even");
b99bd4ef
NC
5339 return;
5340 }
5341
90e4755a 5342 if (rd == REG_LR)
b99bd4ef 5343 {
f2b7cb0a 5344 inst.error = _("r14 not allowed here");
b99bd4ef
NC
5345 return;
5346 }
5347
5348 if (((rd == rn) || (rd + 1 == rn))
90e4755a
RE
5349 && ((inst.instruction & WRITE_BACK)
5350 || (!(inst.instruction & PRE_INDEX))))
b99bd4ef
NC
5351 as_warn (_("pre/post-indexing used when modified address register is destination"));
5352
90e4755a
RE
5353 /* For an index-register load, the index register must not overlap the
5354 destination (even if not write-back). */
5355 if ((inst.instruction & V4_STR_BIT) == 0
5356 && (inst.instruction & HWOFFSET_IMM) == 0)
5357 {
5358 int rm = inst.instruction & 0x0000000f;
5359
5360 if (rm == rd || (rm == rd + 1))
5361 as_warn (_("ldrd destination registers must not overlap index register"));
5362 }
5363
b99bd4ef
NC
5364 end_of_line (str);
5365}
5366
5367/* Returns the index into fp_values of a floating point number,
5368 or -1 if not in the table. */
5369
5370static int
5371my_get_float_expression (str)
5372 char ** str;
5373{
5374 LITTLENUM_TYPE words[MAX_LITTLENUMS];
5375 char * save_in;
5376 expressionS exp;
5377 int i;
5378 int j;
5379
5380 memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
5381
5382 /* Look for a raw floating point number. */
5383 if ((save_in = atof_ieee (*str, 'x', words)) != NULL
5384 && is_end_of_line[(unsigned char) *save_in])
5385 {
5386 for (i = 0; i < NUM_FLOAT_VALS; i++)
5387 {
5388 for (j = 0; j < MAX_LITTLENUMS; j++)
5389 {
5390 if (words[j] != fp_values[i][j])
5391 break;
5392 }
5393
5394 if (j == MAX_LITTLENUMS)
5395 {
5396 *str = save_in;
5397 return i;
5398 }
5399 }
5400 }
5401
5402 /* Try and parse a more complex expression, this will probably fail
5403 unless the code uses a floating point prefix (eg "0f"). */
5404 save_in = input_line_pointer;
5405 input_line_pointer = *str;
5406 if (expression (&exp) == absolute_section
5407 && exp.X_op == O_big
5408 && exp.X_add_number < 0)
5409 {
5410 /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
5411 Ditto for 15. */
5412 if (gen_to_words (words, 5, (long) 15) == 0)
5413 {
5414 for (i = 0; i < NUM_FLOAT_VALS; i++)
5415 {
5416 for (j = 0; j < MAX_LITTLENUMS; j++)
5417 {
5418 if (words[j] != fp_values[i][j])
5419 break;
5420 }
5421
5422 if (j == MAX_LITTLENUMS)
5423 {
5424 *str = input_line_pointer;
5425 input_line_pointer = save_in;
5426 return i;
5427 }
5428 }
5429 }
5430 }
5431
5432 *str = input_line_pointer;
5433 input_line_pointer = save_in;
5434 return -1;
5435}
5436
b34976b6 5437/* Return TRUE if anything in the expression is a bignum. */
b99bd4ef
NC
5438
5439static int
5440walk_no_bignums (sp)
5441 symbolS * sp;
5442{
5443 if (symbol_get_value_expression (sp)->X_op == O_big)
5444 return 1;
5445
5446 if (symbol_get_value_expression (sp)->X_add_symbol)
5447 {
5448 return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
5449 || (symbol_get_value_expression (sp)->X_op_symbol
5450 && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
5451 }
5452
5453 return 0;
5454}
5455
f03698e6
RE
5456static int in_my_get_expression = 0;
5457
b99bd4ef
NC
5458static int
5459my_get_expression (ep, str)
5460 expressionS * ep;
5461 char ** str;
5462{
5463 char * save_in;
5464 segT seg;
5465
5466 save_in = input_line_pointer;
5467 input_line_pointer = *str;
f03698e6 5468 in_my_get_expression = 1;
b99bd4ef 5469 seg = expression (ep);
f03698e6
RE
5470 in_my_get_expression = 0;
5471
5472 if (ep->X_op == O_illegal)
5473 {
5474 /* We found a bad expression in md_operand(). */
5475 *str = input_line_pointer;
5476 input_line_pointer = save_in;
5477 return 1;
5478 }
b99bd4ef
NC
5479
5480#ifdef OBJ_AOUT
5481 if (seg != absolute_section
5482 && seg != text_section
5483 && seg != data_section
5484 && seg != bss_section
5485 && seg != undefined_section)
5486 {
5487 inst.error = _("bad_segment");
5488 *str = input_line_pointer;
5489 input_line_pointer = save_in;
5490 return 1;
5491 }
5492#endif
5493
5494 /* Get rid of any bignums now, so that we don't generate an error for which
5495 we can't establish a line number later on. Big numbers are never valid
5496 in instructions, which is where this routine is always called. */
5497 if (ep->X_op == O_big
5498 || (ep->X_add_symbol
5499 && (walk_no_bignums (ep->X_add_symbol)
5500 || (ep->X_op_symbol
5501 && walk_no_bignums (ep->X_op_symbol)))))
5502 {
f03698e6 5503 inst.error = _("invalid constant");
b99bd4ef
NC
5504 *str = input_line_pointer;
5505 input_line_pointer = save_in;
5506 return 1;
5507 }
5508
5509 *str = input_line_pointer;
5510 input_line_pointer = save_in;
5511 return 0;
5512}
5513
cc8a6dd0 5514/* We handle all bad expressions here, so that we can report the faulty
f03698e6
RE
5515 instruction in the error message. */
5516void
ce058b6c 5517md_operand (expr)
f03698e6
RE
5518 expressionS *expr;
5519{
5520 if (in_my_get_expression)
5521 {
5522 expr->X_op = O_illegal;
5523 if (inst.error == NULL)
5524 inst.error = _("bad expression");
5525 }
5526}
5527
b99bd4ef
NC
5528/* UNRESTRICT should be one if <shift> <register> is permitted for this
5529 instruction. */
5530
5531static int
5532decode_shift (str, unrestrict)
5533 char ** str;
5534 int unrestrict;
5535{
5536 const struct asm_shift_name * shift;
5537 char * p;
5538 char c;
5539
5540 skip_whitespace (* str);
5541
3882b010 5542 for (p = * str; ISALPHA (* p); p ++)
b99bd4ef
NC
5543 ;
5544
5545 if (p == * str)
5546 {
f03698e6 5547 inst.error = _("shift expression expected");
b99bd4ef
NC
5548 return FAIL;
5549 }
5550
5551 c = * p;
5552 * p = '\0';
5553 shift = (const struct asm_shift_name *) hash_find (arm_shift_hsh, * str);
5554 * p = c;
5555
5556 if (shift == NULL)
5557 {
f03698e6 5558 inst.error = _("shift expression expected");
b99bd4ef
NC
5559 return FAIL;
5560 }
5561
5562 assert (shift->properties->index == shift_properties[shift->properties->index].index);
5563
5564 if (shift->properties->index == SHIFT_RRX)
5565 {
5566 * str = p;
5567 inst.instruction |= shift->properties->bit_field;
5568 return SUCCESS;
5569 }
5570
5571 skip_whitespace (p);
5572
5573 if (unrestrict && reg_required_here (& p, 8) != FAIL)
5574 {
5575 inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG;
5576 * str = p;
5577 return SUCCESS;
5578 }
5579 else if (! is_immediate_prefix (* p))
5580 {
5581 inst.error = (unrestrict
5582 ? _("shift requires register or #expression")
5583 : _("shift requires #expression"));
5584 * str = p;
5585 return FAIL;
5586 }
5587
5588 inst.error = NULL;
5589 p ++;
5590
5591 if (my_get_expression (& inst.reloc.exp, & p))
5592 return FAIL;
5593
5594 /* Validate some simple #expressions. */
5595 if (inst.reloc.exp.X_op == O_constant)
5596 {
5597 unsigned num = inst.reloc.exp.X_add_number;
5598
5599 /* Reject operations greater than 32. */
5600 if (num > 32
5601 /* Reject a shift of 0 unless the mode allows it. */
5602 || (num == 0 && shift->properties->allows_0 == 0)
5603 /* Reject a shift of 32 unless the mode allows it. */
5604 || (num == 32 && shift->properties->allows_32 == 0)
5605 )
5606 {
5607 /* As a special case we allow a shift of zero for
5608 modes that do not support it to be recoded as an
5609 logical shift left of zero (ie nothing). We warn
5610 about this though. */
5611 if (num == 0)
5612 {
f03698e6 5613 as_warn (_("shift of 0 ignored."));
b99bd4ef
NC
5614 shift = & shift_names[0];
5615 assert (shift->properties->index == SHIFT_LSL);
5616 }
5617 else
5618 {
f03698e6 5619 inst.error = _("invalid immediate shift");
b99bd4ef
NC
5620 return FAIL;
5621 }
5622 }
5623
5624 /* Shifts of 32 are encoded as 0, for those shifts that
5625 support it. */
5626 if (num == 32)
5627 num = 0;
5628
5629 inst.instruction |= (num << 7) | shift->properties->bit_field;
5630 }
5631 else
5632 {
5633 inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
5634 inst.reloc.pc_rel = 0;
5635 inst.instruction |= shift->properties->bit_field;
5636 }
5637
5638 * str = p;
5639 return SUCCESS;
5640}
5641
5642/* Do those data_ops which can take a negative immediate constant
5643 by altering the instuction. A bit of a hack really.
5644 MOV <-> MVN
5645 AND <-> BIC
5646 ADC <-> SBC
5647 by inverting the second operand, and
5648 ADD <-> SUB
5649 CMP <-> CMN
5650 by negating the second operand. */
5651
5652static int
5653negate_data_op (instruction, value)
5654 unsigned long * instruction;
5655 unsigned long value;
5656{
5657 int op, new_inst;
5658 unsigned long negated, inverted;
5659
5660 negated = validate_immediate (-value);
5661 inverted = validate_immediate (~value);
5662
5663 op = (*instruction >> DATA_OP_SHIFT) & 0xf;
5664 switch (op)
5665 {
5666 /* First negates. */
5667 case OPCODE_SUB: /* ADD <-> SUB */
5668 new_inst = OPCODE_ADD;
5669 value = negated;
5670 break;
5671
5672 case OPCODE_ADD:
5673 new_inst = OPCODE_SUB;
5674 value = negated;
5675 break;
5676
5677 case OPCODE_CMP: /* CMP <-> CMN */
5678 new_inst = OPCODE_CMN;
5679 value = negated;
5680 break;
5681
5682 case OPCODE_CMN:
5683 new_inst = OPCODE_CMP;
5684 value = negated;
5685 break;
5686
5687 /* Now Inverted ops. */
5688 case OPCODE_MOV: /* MOV <-> MVN */
5689 new_inst = OPCODE_MVN;
5690 value = inverted;
5691 break;
5692
5693 case OPCODE_MVN:
5694 new_inst = OPCODE_MOV;
5695 value = inverted;
5696 break;
5697
5698 case OPCODE_AND: /* AND <-> BIC */
5699 new_inst = OPCODE_BIC;
5700 value = inverted;
5701 break;
5702
5703 case OPCODE_BIC:
5704 new_inst = OPCODE_AND;
5705 value = inverted;
5706 break;
5707
5708 case OPCODE_ADC: /* ADC <-> SBC */
5709 new_inst = OPCODE_SBC;
5710 value = inverted;
5711 break;
5712
5713 case OPCODE_SBC:
5714 new_inst = OPCODE_ADC;
5715 value = inverted;
5716 break;
5717
5718 /* We cannot do anything. */
5719 default:
5720 return FAIL;
5721 }
5722
5723 if (value == (unsigned) FAIL)
5724 return FAIL;
5725
5726 *instruction &= OPCODE_MASK;
5727 *instruction |= new_inst << DATA_OP_SHIFT;
5728 return value;
5729}
5730
5731static int
5732data_op2 (str)
5733 char ** str;
5734{
5735 int value;
5736 expressionS expr;
5737
5738 skip_whitespace (* str);
5739
5740 if (reg_required_here (str, 0) != FAIL)
5741 {
5742 if (skip_past_comma (str) == SUCCESS)
5743 /* Shift operation on register. */
5744 return decode_shift (str, NO_SHIFT_RESTRICT);
5745
5746 return SUCCESS;
5747 }
5748 else
5749 {
5750 /* Immediate expression. */
5751 if (is_immediate_prefix (**str))
5752 {
5753 (*str)++;
5754 inst.error = NULL;
5755
5756 if (my_get_expression (&inst.reloc.exp, str))
5757 return FAIL;
5758
5759 if (inst.reloc.exp.X_add_symbol)
5760 {
5761 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
5762 inst.reloc.pc_rel = 0;
5763 }
5764 else
5765 {
5766 if (skip_past_comma (str) == SUCCESS)
5767 {
5768 /* #x, y -- ie explicit rotation by Y. */
5769 if (my_get_expression (&expr, str))
5770 return FAIL;
5771
5772 if (expr.X_op != O_constant)
5773 {
f03698e6 5774 inst.error = _("constant expression expected");
b99bd4ef
NC
5775 return FAIL;
5776 }
5777
5778 /* Rotate must be a multiple of 2. */
5779 if (((unsigned) expr.X_add_number) > 30
5780 || (expr.X_add_number & 1) != 0
5781 || ((unsigned) inst.reloc.exp.X_add_number) > 255)
5782 {
f03698e6 5783 inst.error = _("invalid constant");
b99bd4ef
NC
5784 return FAIL;
5785 }
5786 inst.instruction |= INST_IMMEDIATE;
5787 inst.instruction |= inst.reloc.exp.X_add_number;
5788 inst.instruction |= expr.X_add_number << 7;
5789 return SUCCESS;
5790 }
5791
5792 /* Implicit rotation, select a suitable one. */
5793 value = validate_immediate (inst.reloc.exp.X_add_number);
5794
5795 if (value == FAIL)
5796 {
5797 /* Can't be done. Perhaps the code reads something like
5798 "add Rd, Rn, #-n", where "sub Rd, Rn, #n" would be OK. */
5799 if ((value = negate_data_op (&inst.instruction,
5800 inst.reloc.exp.X_add_number))
5801 == FAIL)
5802 {
f03698e6 5803 inst.error = _("invalid constant");
b99bd4ef
NC
5804 return FAIL;
5805 }
5806 }
5807
5808 inst.instruction |= value;
5809 }
5810
5811 inst.instruction |= INST_IMMEDIATE;
5812 return SUCCESS;
5813 }
5814
5815 (*str)++;
f03698e6 5816 inst.error = _("register or shift expression expected");
b99bd4ef
NC
5817 return FAIL;
5818 }
5819}
5820
5821static int
5822fp_op2 (str)
5823 char ** str;
5824{
5825 skip_whitespace (* str);
5826
5827 if (fp_reg_required_here (str, 0) != FAIL)
5828 return SUCCESS;
5829 else
5830 {
5831 /* Immediate expression. */
5832 if (*((*str)++) == '#')
5833 {
5834 int i;
5835
5836 inst.error = NULL;
5837
5838 skip_whitespace (* str);
5839
5840 /* First try and match exact strings, this is to guarantee
5841 that some formats will work even for cross assembly. */
5842
5843 for (i = 0; fp_const[i]; i++)
5844 {
5845 if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
5846 {
5847 char *start = *str;
5848
5849 *str += strlen (fp_const[i]);
5850 if (is_end_of_line[(unsigned char) **str])
5851 {
5852 inst.instruction |= i + 8;
5853 return SUCCESS;
5854 }
5855 *str = start;
5856 }
5857 }
5858
5859 /* Just because we didn't get a match doesn't mean that the
5860 constant isn't valid, just that it is in a format that we
5861 don't automatically recognize. Try parsing it with
5862 the standard expression routines. */
5863 if ((i = my_get_float_expression (str)) >= 0)
5864 {
5865 inst.instruction |= i + 8;
5866 return SUCCESS;
5867 }
5868
f03698e6 5869 inst.error = _("invalid floating point immediate expression");
b99bd4ef
NC
5870 return FAIL;
5871 }
5872 inst.error =
f03698e6 5873 _("floating point register or immediate expression expected");
b99bd4ef
NC
5874 return FAIL;
5875 }
5876}
5877
5878static void
f2b7cb0a 5879do_arit (str)
b99bd4ef 5880 char * str;
b99bd4ef
NC
5881{
5882 skip_whitespace (str);
5883
5884 if (reg_required_here (&str, 12) == FAIL
5885 || skip_past_comma (&str) == FAIL
5886 || reg_required_here (&str, 16) == FAIL
5887 || skip_past_comma (&str) == FAIL
5888 || data_op2 (&str) == FAIL)
5889 {
5890 if (!inst.error)
5891 inst.error = BAD_ARGS;
5892 return;
5893 }
5894
b99bd4ef
NC
5895 end_of_line (str);
5896 return;
5897}
5898
5899static void
f2b7cb0a 5900do_adr (str)
b99bd4ef 5901 char * str;
b99bd4ef 5902{
90e4755a
RE
5903 /* This is a pseudo-op of the form "adr rd, label" to be converted
5904 into a relative address of the form "add rd, pc, #label-.-8". */
5905 skip_whitespace (str);
5906
5907 if (reg_required_here (&str, 12) == FAIL
5908 || skip_past_comma (&str) == FAIL
5909 || my_get_expression (&inst.reloc.exp, &str))
5910 {
5911 if (!inst.error)
5912 inst.error = BAD_ARGS;
5913 return;
5914 }
5915
5916 /* Frag hacking will turn this into a sub instruction if the offset turns
5917 out to be negative. */
5918 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
5919 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust. */
5920 inst.reloc.pc_rel = 1;
5921
5922 end_of_line (str);
5923}
5924
5925static void
f2b7cb0a 5926do_adrl (str)
90e4755a 5927 char * str;
90e4755a
RE
5928{
5929 /* This is a pseudo-op of the form "adrl rd, label" to be converted
5930 into a relative address of the form:
5931 add rd, pc, #low(label-.-8)"
5932 add rd, rd, #high(label-.-8)" */
5933
5934 skip_whitespace (str);
5935
5936 if (reg_required_here (&str, 12) == FAIL
5937 || skip_past_comma (&str) == FAIL
5938 || my_get_expression (&inst.reloc.exp, &str))
5939 {
5940 if (!inst.error)
5941 inst.error = BAD_ARGS;
5942
5943 return;
5944 }
5945
5946 end_of_line (str);
5947 /* Frag hacking will turn this into a sub instruction if the offset turns
5948 out to be negative. */
5949 inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
5950 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
5951 inst.reloc.pc_rel = 1;
5952 inst.size = INSN_SIZE * 2;
5953
5954 return;
5955}
5956
5957static void
f2b7cb0a 5958do_cmp (str)
90e4755a 5959 char * str;
90e4755a
RE
5960{
5961 skip_whitespace (str);
5962
5963 if (reg_required_here (&str, 16) == FAIL)
5964 {
5965 if (!inst.error)
5966 inst.error = BAD_ARGS;
5967 return;
5968 }
5969
5970 if (skip_past_comma (&str) == FAIL
5971 || data_op2 (&str) == FAIL)
5972 {
5973 if (!inst.error)
5974 inst.error = BAD_ARGS;
5975 return;
5976 }
5977
90e4755a
RE
5978 end_of_line (str);
5979 return;
5980}
5981
5982static void
f2b7cb0a 5983do_mov (str)
90e4755a 5984 char * str;
90e4755a
RE
5985{
5986 skip_whitespace (str);
5987
5988 if (reg_required_here (&str, 12) == FAIL)
5989 {
5990 if (!inst.error)
5991 inst.error = BAD_ARGS;
5992 return;
5993 }
5994
5995 if (skip_past_comma (&str) == FAIL
5996 || data_op2 (&str) == FAIL)
5997 {
5998 if (!inst.error)
5999 inst.error = BAD_ARGS;
6000 return;
6001 }
6002
90e4755a
RE
6003 end_of_line (str);
6004 return;
6005}
6006
6007static int
6008ldst_extend (str)
6009 char ** str;
6010{
6011 int add = INDEX_UP;
6012
6013 switch (**str)
6014 {
6015 case '#':
6016 case '$':
6017 (*str)++;
6018 if (my_get_expression (& inst.reloc.exp, str))
6019 return FAIL;
6020
6021 if (inst.reloc.exp.X_op == O_constant)
6022 {
6023 int value = inst.reloc.exp.X_add_number;
6024
6025 if (value < -4095 || value > 4095)
6026 {
6027 inst.error = _("address offset too large");
6028 return FAIL;
6029 }
6030
6031 if (value < 0)
6032 {
6033 value = -value;
6034 add = 0;
6035 }
6036
6037 inst.instruction |= add | value;
6038 }
6039 else
6040 {
6041 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6042 inst.reloc.pc_rel = 0;
6043 }
6044 return SUCCESS;
6045
6046 case '-':
6047 add = 0;
6048 /* Fall through. */
6049
6050 case '+':
6051 (*str)++;
6052 /* Fall through. */
6053
6054 default:
6055 if (reg_required_here (str, 0) == FAIL)
6056 return FAIL;
6057
6058 inst.instruction |= add | OFFSET_REG;
6059 if (skip_past_comma (str) == SUCCESS)
6060 return decode_shift (str, SHIFT_RESTRICT);
6061
6062 return SUCCESS;
6063 }
6064}
6065
6066static void
f2b7cb0a 6067do_ldst (str)
90e4755a 6068 char * str;
90e4755a
RE
6069{
6070 int pre_inc = 0;
6071 int conflict_reg;
6072 int value;
6073
b99bd4ef
NC
6074 skip_whitespace (str);
6075
90e4755a
RE
6076 if ((conflict_reg = reg_required_here (&str, 12)) == FAIL)
6077 {
6078 if (!inst.error)
6079 inst.error = BAD_ARGS;
6080 return;
6081 }
6082
6083 if (skip_past_comma (&str) == FAIL)
6084 {
f03698e6 6085 inst.error = _("address expected");
90e4755a
RE
6086 return;
6087 }
6088
90e4755a
RE
6089 if (*str == '[')
6090 {
6091 int reg;
6092
6093 str++;
6094
6095 skip_whitespace (str);
6096
6097 if ((reg = reg_required_here (&str, 16)) == FAIL)
6098 return;
6099
6100 /* Conflicts can occur on stores as well as loads. */
6101 conflict_reg = (conflict_reg == reg);
6102
6103 skip_whitespace (str);
6104
6105 if (*str == ']')
6106 {
6107 str ++;
6108
6109 if (skip_past_comma (&str) == SUCCESS)
6110 {
6111 /* [Rn],... (post inc) */
6112 if (ldst_extend (&str) == FAIL)
6113 return;
6114 if (conflict_reg)
6115 as_warn (_("%s register same as write-back base"),
6116 ((inst.instruction & LOAD_BIT)
6117 ? _("destination") : _("source")));
6118 }
6119 else
6120 {
6121 /* [Rn] */
6122 skip_whitespace (str);
6123
6124 if (*str == '!')
6125 {
6126 if (conflict_reg)
6127 as_warn (_("%s register same as write-back base"),
6128 ((inst.instruction & LOAD_BIT)
6129 ? _("destination") : _("source")));
6130 str++;
6131 inst.instruction |= WRITE_BACK;
6132 }
6133
6134 inst.instruction |= INDEX_UP;
6135 pre_inc = 1;
6136 }
6137 }
6138 else
6139 {
6140 /* [Rn,...] */
6141 if (skip_past_comma (&str) == FAIL)
6142 {
6143 inst.error = _("pre-indexed expression expected");
6144 return;
6145 }
6146
6147 pre_inc = 1;
6148 if (ldst_extend (&str) == FAIL)
6149 return;
6150
6151 skip_whitespace (str);
6152
6153 if (*str++ != ']')
6154 {
6155 inst.error = _("missing ]");
6156 return;
6157 }
6158
6159 skip_whitespace (str);
6160
6161 if (*str == '!')
6162 {
6163 if (conflict_reg)
6164 as_warn (_("%s register same as write-back base"),
6165 ((inst.instruction & LOAD_BIT)
6166 ? _("destination") : _("source")));
6167 str++;
6168 inst.instruction |= WRITE_BACK;
6169 }
6170 }
6171 }
6172 else if (*str == '=')
6173 {
f03698e6
RE
6174 if ((inst.instruction & LOAD_BIT) == 0)
6175 {
6176 inst.error = _("invalid pseudo operation");
6177 return;
6178 }
6179
90e4755a
RE
6180 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6181 str++;
6182
6183 skip_whitespace (str);
6184
6185 if (my_get_expression (&inst.reloc.exp, &str))
6186 return;
6187
6188 if (inst.reloc.exp.X_op != O_constant
6189 && inst.reloc.exp.X_op != O_symbol)
6190 {
f03698e6 6191 inst.error = _("constant expression expected");
90e4755a
RE
6192 return;
6193 }
6194
e28cd48c 6195 if (inst.reloc.exp.X_op == O_constant)
90e4755a 6196 {
e28cd48c
RE
6197 value = validate_immediate (inst.reloc.exp.X_add_number);
6198
6199 if (value != FAIL)
90e4755a 6200 {
e28cd48c
RE
6201 /* This can be done with a mov instruction. */
6202 inst.instruction &= LITERAL_MASK;
6203 inst.instruction |= (INST_IMMEDIATE
6204 | (OPCODE_MOV << DATA_OP_SHIFT));
6205 inst.instruction |= value & 0xfff;
6206 end_of_line (str);
90e4755a
RE
6207 return;
6208 }
b99bd4ef 6209
e28cd48c
RE
6210 value = validate_immediate (~inst.reloc.exp.X_add_number);
6211
6212 if (value != FAIL)
6213 {
6214 /* This can be done with a mvn instruction. */
6215 inst.instruction &= LITERAL_MASK;
6216 inst.instruction |= (INST_IMMEDIATE
6217 | (OPCODE_MVN << DATA_OP_SHIFT));
6218 inst.instruction |= value & 0xfff;
6219 end_of_line (str);
6220 return;
6221 }
90e4755a 6222 }
e28cd48c
RE
6223
6224 /* Insert into literal pool. */
6225 if (add_to_lit_pool () == FAIL)
6226 {
6227 if (!inst.error)
6228 inst.error = _("literal pool insertion failed");
6229 return;
6230 }
6231
6232 /* Change the instruction exp to point to the pool. */
6233 inst.reloc.type = BFD_RELOC_ARM_LITERAL;
6234 inst.reloc.pc_rel = 1;
6235 inst.instruction |= (REG_PC << 16);
6236 pre_inc = 1;
1cac9012
NC
6237 }
6238 else
6239 {
90e4755a
RE
6240 if (my_get_expression (&inst.reloc.exp, &str))
6241 return;
6242
6243 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6244#ifndef TE_WINCE
6245 /* PC rel adjust. */
6246 inst.reloc.exp.X_add_number -= 8;
6247#endif
1cac9012 6248 inst.reloc.pc_rel = 1;
90e4755a
RE
6249 inst.instruction |= (REG_PC << 16);
6250 pre_inc = 1;
b99bd4ef
NC
6251 }
6252
90e4755a 6253 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef 6254 end_of_line (str);
90e4755a 6255 return;
b99bd4ef
NC
6256}
6257
6258static void
f2b7cb0a 6259do_ldstt (str)
90e4755a 6260 char * str;
b99bd4ef 6261{
90e4755a
RE
6262 int conflict_reg;
6263
b99bd4ef
NC
6264 skip_whitespace (str);
6265
90e4755a 6266 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
b99bd4ef
NC
6267 {
6268 if (!inst.error)
6269 inst.error = BAD_ARGS;
6270 return;
6271 }
6272
90e4755a 6273 if (skip_past_comma (& str) == FAIL)
b99bd4ef 6274 {
f03698e6 6275 inst.error = _("address expected");
b99bd4ef
NC
6276 return;
6277 }
6278
90e4755a
RE
6279 if (*str == '[')
6280 {
6281 int reg;
b99bd4ef 6282
90e4755a 6283 str++;
b99bd4ef 6284
90e4755a 6285 skip_whitespace (str);
b99bd4ef 6286
90e4755a
RE
6287 if ((reg = reg_required_here (&str, 16)) == FAIL)
6288 return;
b99bd4ef 6289
90e4755a
RE
6290 /* ldrt/strt always use post-indexed addressing, so if the base is
6291 the same as Rd, we warn. */
6292 if (conflict_reg == reg)
6293 as_warn (_("%s register same as write-back base"),
6294 ((inst.instruction & LOAD_BIT)
6295 ? _("destination") : _("source")));
6296
6297 skip_whitespace (str);
6298
6299 if (*str == ']')
6300 {
6301 str ++;
6302
6303 if (skip_past_comma (&str) == SUCCESS)
6304 {
6305 /* [Rn],... (post inc) */
6306 if (ldst_extend (&str) == FAIL)
6307 return;
6308 }
6309 else
6310 {
6311 /* [Rn] */
6312 skip_whitespace (str);
6313
6314 /* Skip a write-back '!'. */
6315 if (*str == '!')
6316 str++;
6317
6318 inst.instruction |= INDEX_UP;
6319 }
6320 }
6321 else
6322 {
6323 inst.error = _("post-indexed expression expected");
6324 return;
6325 }
6326 }
6327 else
b99bd4ef 6328 {
90e4755a 6329 inst.error = _("post-indexed expression expected");
b99bd4ef
NC
6330 return;
6331 }
6332
b99bd4ef
NC
6333 end_of_line (str);
6334 return;
6335}
6336
6337static int
90e4755a 6338ldst_extend_v4 (str)
b99bd4ef 6339 char ** str;
b99bd4ef
NC
6340{
6341 int add = INDEX_UP;
6342
6343 switch (**str)
6344 {
6345 case '#':
6346 case '$':
6347 (*str)++;
6348 if (my_get_expression (& inst.reloc.exp, str))
6349 return FAIL;
6350
6351 if (inst.reloc.exp.X_op == O_constant)
6352 {
6353 int value = inst.reloc.exp.X_add_number;
6354
90e4755a 6355 if (value < -255 || value > 255)
b99bd4ef
NC
6356 {
6357 inst.error = _("address offset too large");
6358 return FAIL;
6359 }
6360
6361 if (value < 0)
6362 {
6363 value = -value;
6364 add = 0;
6365 }
6366
6367 /* Halfword and signextension instructions have the
6368 immediate value split across bits 11..8 and bits 3..0. */
90e4755a
RE
6369 inst.instruction |= (add | HWOFFSET_IMM
6370 | ((value >> 4) << 8) | (value & 0xF));
b99bd4ef
NC
6371 }
6372 else
6373 {
90e4755a
RE
6374 inst.instruction |= HWOFFSET_IMM;
6375 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
b99bd4ef
NC
6376 inst.reloc.pc_rel = 0;
6377 }
6378 return SUCCESS;
6379
6380 case '-':
6381 add = 0;
6382 /* Fall through. */
6383
6384 case '+':
6385 (*str)++;
6386 /* Fall through. */
6387
6388 default:
6389 if (reg_required_here (str, 0) == FAIL)
6390 return FAIL;
6391
90e4755a 6392 inst.instruction |= add;
b99bd4ef
NC
6393 return SUCCESS;
6394 }
6395}
6396
90e4755a 6397/* Halfword and signed-byte load/store operations. */
b99bd4ef 6398static void
f2b7cb0a 6399do_ldstv4 (str)
b99bd4ef 6400 char * str;
b99bd4ef 6401{
b99bd4ef
NC
6402 int pre_inc = 0;
6403 int conflict_reg;
6404 int value;
6405
b99bd4ef
NC
6406 skip_whitespace (str);
6407
6408 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
6409 {
6410 if (!inst.error)
6411 inst.error = BAD_ARGS;
6412 return;
6413 }
6414
6415 if (skip_past_comma (& str) == FAIL)
6416 {
f03698e6 6417 inst.error = _("address expected");
b99bd4ef
NC
6418 return;
6419 }
6420
6421 if (*str == '[')
6422 {
6423 int reg;
6424
6425 str++;
6426
6427 skip_whitespace (str);
6428
6429 if ((reg = reg_required_here (&str, 16)) == FAIL)
6430 return;
6431
6432 /* Conflicts can occur on stores as well as loads. */
6433 conflict_reg = (conflict_reg == reg);
6434
6435 skip_whitespace (str);
6436
6437 if (*str == ']')
6438 {
6439 str ++;
6440
6441 if (skip_past_comma (&str) == SUCCESS)
6442 {
6443 /* [Rn],... (post inc) */
90e4755a 6444 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6445 return;
6446 if (conflict_reg)
90e4755a
RE
6447 as_warn (_("%s register same as write-back base"),
6448 ((inst.instruction & LOAD_BIT)
6449 ? _("destination") : _("source")));
b99bd4ef
NC
6450 }
6451 else
6452 {
6453 /* [Rn] */
90e4755a 6454 inst.instruction |= HWOFFSET_IMM;
b99bd4ef
NC
6455
6456 skip_whitespace (str);
6457
6458 if (*str == '!')
6459 {
6460 if (conflict_reg)
6461 as_warn (_("%s register same as write-back base"),
6462 ((inst.instruction & LOAD_BIT)
6463 ? _("destination") : _("source")));
6464 str++;
6465 inst.instruction |= WRITE_BACK;
6466 }
6467
90e4755a
RE
6468 inst.instruction |= INDEX_UP;
6469 pre_inc = 1;
b99bd4ef
NC
6470 }
6471 }
6472 else
6473 {
6474 /* [Rn,...] */
6475 if (skip_past_comma (&str) == FAIL)
6476 {
6477 inst.error = _("pre-indexed expression expected");
6478 return;
6479 }
6480
6481 pre_inc = 1;
90e4755a 6482 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6483 return;
6484
6485 skip_whitespace (str);
6486
6487 if (*str++ != ']')
6488 {
6489 inst.error = _("missing ]");
6490 return;
6491 }
6492
6493 skip_whitespace (str);
6494
6495 if (*str == '!')
6496 {
6497 if (conflict_reg)
6498 as_warn (_("%s register same as write-back base"),
6499 ((inst.instruction & LOAD_BIT)
6500 ? _("destination") : _("source")));
6501 str++;
6502 inst.instruction |= WRITE_BACK;
6503 }
6504 }
6505 }
6506 else if (*str == '=')
6507 {
f03698e6
RE
6508 if ((inst.instruction & LOAD_BIT) == 0)
6509 {
6510 inst.error = _("invalid pseudo operation");
6511 return;
6512 }
6513
90e4755a 6514 /* XXX Does this work correctly for half-word/byte ops? */
b99bd4ef
NC
6515 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6516 str++;
6517
6518 skip_whitespace (str);
6519
6520 if (my_get_expression (&inst.reloc.exp, &str))
6521 return;
6522
6523 if (inst.reloc.exp.X_op != O_constant
6524 && inst.reloc.exp.X_op != O_symbol)
6525 {
f03698e6 6526 inst.error = _("constant expression expected");
b99bd4ef
NC
6527 return;
6528 }
6529
d8273442 6530 if (inst.reloc.exp.X_op == O_constant)
b99bd4ef 6531 {
d8273442
NC
6532 value = validate_immediate (inst.reloc.exp.X_add_number);
6533
6534 if (value != FAIL)
b99bd4ef 6535 {
d8273442
NC
6536 /* This can be done with a mov instruction. */
6537 inst.instruction &= LITERAL_MASK;
6538 inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
90e4755a 6539 inst.instruction |= value & 0xfff;
d8273442 6540 end_of_line (str);
b99bd4ef
NC
6541 return;
6542 }
cc8a6dd0 6543
d8273442 6544 value = validate_immediate (~ inst.reloc.exp.X_add_number);
b99bd4ef 6545
d8273442 6546 if (value != FAIL)
b99bd4ef 6547 {
d8273442
NC
6548 /* This can be done with a mvn instruction. */
6549 inst.instruction &= LITERAL_MASK;
6550 inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
90e4755a 6551 inst.instruction |= value & 0xfff;
d8273442
NC
6552 end_of_line (str);
6553 return;
b99bd4ef 6554 }
b99bd4ef 6555 }
d8273442
NC
6556
6557 /* Insert into literal pool. */
6558 if (add_to_lit_pool () == FAIL)
6559 {
6560 if (!inst.error)
6561 inst.error = _("literal pool insertion failed");
6562 return;
6563 }
6564
6565 /* Change the instruction exp to point to the pool. */
90e4755a
RE
6566 inst.instruction |= HWOFFSET_IMM;
6567 inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
d8273442
NC
6568 inst.reloc.pc_rel = 1;
6569 inst.instruction |= (REG_PC << 16);
6570 pre_inc = 1;
b99bd4ef
NC
6571 }
6572 else
6573 {
6574 if (my_get_expression (&inst.reloc.exp, &str))
6575 return;
6576
90e4755a
RE
6577 inst.instruction |= HWOFFSET_IMM;
6578 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
b99bd4ef
NC
6579#ifndef TE_WINCE
6580 /* PC rel adjust. */
6581 inst.reloc.exp.X_add_number -= 8;
6582#endif
6583 inst.reloc.pc_rel = 1;
6584 inst.instruction |= (REG_PC << 16);
6585 pre_inc = 1;
6586 }
6587
90e4755a 6588 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef
NC
6589 end_of_line (str);
6590 return;
6591}
6592
6593static long
6594reg_list (strp)
6595 char ** strp;
6596{
6597 char * str = * strp;
6598 long range = 0;
6599 int another_range;
6600
6601 /* We come back here if we get ranges concatenated by '+' or '|'. */
6602 do
6603 {
6604 another_range = 0;
6605
6606 if (*str == '{')
6607 {
6608 int in_range = 0;
6609 int cur_reg = -1;
6610
6611 str++;
6612 do
6613 {
6614 int reg;
6615
6616 skip_whitespace (str);
6617
6618 if ((reg = reg_required_here (& str, -1)) == FAIL)
6619 return FAIL;
6620
6621 if (in_range)
6622 {
6623 int i;
6624
6625 if (reg <= cur_reg)
6626 {
f03698e6 6627 inst.error = _("bad range in register list");
b99bd4ef
NC
6628 return FAIL;
6629 }
6630
6631 for (i = cur_reg + 1; i < reg; i++)
6632 {
6633 if (range & (1 << i))
6634 as_tsktsk
f03698e6 6635 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6636 i);
6637 else
6638 range |= 1 << i;
6639 }
6640 in_range = 0;
6641 }
6642
6643 if (range & (1 << reg))
f03698e6 6644 as_tsktsk (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6645 reg);
6646 else if (reg <= cur_reg)
f03698e6 6647 as_tsktsk (_("Warning: register range not in ascending order"));
b99bd4ef
NC
6648
6649 range |= 1 << reg;
6650 cur_reg = reg;
6651 }
6652 while (skip_past_comma (&str) != FAIL
6653 || (in_range = 1, *str++ == '-'));
6654 str--;
6655 skip_whitespace (str);
6656
6657 if (*str++ != '}')
6658 {
f03698e6 6659 inst.error = _("missing `}'");
b99bd4ef
NC
6660 return FAIL;
6661 }
6662 }
6663 else
6664 {
6665 expressionS expr;
6666
6667 if (my_get_expression (&expr, &str))
6668 return FAIL;
6669
6670 if (expr.X_op == O_constant)
6671 {
6672 if (expr.X_add_number
6673 != (expr.X_add_number & 0x0000ffff))
6674 {
6675 inst.error = _("invalid register mask");
6676 return FAIL;
6677 }
6678
6679 if ((range & expr.X_add_number) != 0)
6680 {
6681 int regno = range & expr.X_add_number;
6682
6683 regno &= -regno;
6684 regno = (1 << regno) - 1;
6685 as_tsktsk
f03698e6 6686 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6687 regno);
6688 }
6689
6690 range |= expr.X_add_number;
6691 }
6692 else
6693 {
6694 if (inst.reloc.type != 0)
6695 {
6696 inst.error = _("expression too complex");
6697 return FAIL;
6698 }
6699
6700 memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
6701 inst.reloc.type = BFD_RELOC_ARM_MULTI;
6702 inst.reloc.pc_rel = 0;
6703 }
6704 }
6705
6706 skip_whitespace (str);
6707
6708 if (*str == '|' || *str == '+')
6709 {
6710 str++;
6711 another_range = 1;
6712 }
6713 }
6714 while (another_range);
6715
6716 *strp = str;
6717 return range;
6718}
6719
6720static void
f2b7cb0a 6721do_ldmstm (str)
b99bd4ef 6722 char * str;
b99bd4ef
NC
6723{
6724 int base_reg;
6725 long range;
6726
6727 skip_whitespace (str);
6728
6729 if ((base_reg = reg_required_here (&str, 16)) == FAIL)
6730 return;
6731
6732 if (base_reg == REG_PC)
6733 {
6734 inst.error = _("r15 not allowed as base register");
6735 return;
6736 }
6737
6738 skip_whitespace (str);
6739
6740 if (*str == '!')
6741 {
90e4755a 6742 inst.instruction |= WRITE_BACK;
b99bd4ef
NC
6743 str++;
6744 }
6745
6746 if (skip_past_comma (&str) == FAIL
6747 || (range = reg_list (&str)) == FAIL)
6748 {
6749 if (! inst.error)
6750 inst.error = BAD_ARGS;
6751 return;
6752 }
6753
6754 if (*str == '^')
6755 {
6756 str++;
90e4755a 6757 inst.instruction |= LDM_TYPE_2_OR_3;
b99bd4ef
NC
6758 }
6759
6189168b
NC
6760 if (inst.instruction & WRITE_BACK)
6761 {
6762 /* Check for unpredictable uses of writeback. */
6763 if (inst.instruction & LOAD_BIT)
6764 {
6765 /* Not allowed in LDM type 2. */
6766 if ((inst.instruction & LDM_TYPE_2_OR_3)
6767 && ((range & (1 << REG_PC)) == 0))
6768 as_warn (_("writeback of base register is UNPREDICTABLE"));
6769 /* Only allowed if base reg not in list for other types. */
6770 else if (range & (1 << base_reg))
6771 as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
6772 }
6773 else /* STM. */
6774 {
6775 /* Not allowed for type 2. */
6776 if (inst.instruction & LDM_TYPE_2_OR_3)
6777 as_warn (_("writeback of base register is UNPREDICTABLE"));
6778 /* Only allowed if base reg not in list, or first in list. */
6779 else if ((range & (1 << base_reg))
6780 && (range & ((1 << base_reg) - 1)))
6781 as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
6782 }
6783 }
61b5f74b 6784
f2b7cb0a 6785 inst.instruction |= range;
b99bd4ef
NC
6786 end_of_line (str);
6787 return;
6788}
6789
6790static void
f2b7cb0a 6791do_swi (str)
b99bd4ef 6792 char * str;
b99bd4ef
NC
6793{
6794 skip_whitespace (str);
6795
6796 /* Allow optional leading '#'. */
6797 if (is_immediate_prefix (*str))
6798 str++;
6799
6800 if (my_get_expression (& inst.reloc.exp, & str))
6801 return;
6802
6803 inst.reloc.type = BFD_RELOC_ARM_SWI;
6804 inst.reloc.pc_rel = 0;
b99bd4ef
NC
6805 end_of_line (str);
6806
6807 return;
6808}
6809
6810static void
f2b7cb0a 6811do_swap (str)
b99bd4ef 6812 char * str;
b99bd4ef
NC
6813{
6814 int reg;
6815
6816 skip_whitespace (str);
6817
6818 if ((reg = reg_required_here (&str, 12)) == FAIL)
6819 return;
6820
6821 if (reg == REG_PC)
6822 {
6823 inst.error = _("r15 not allowed in swap");
6824 return;
6825 }
6826
6827 if (skip_past_comma (&str) == FAIL
6828 || (reg = reg_required_here (&str, 0)) == FAIL)
6829 {
6830 if (!inst.error)
6831 inst.error = BAD_ARGS;
6832 return;
6833 }
6834
6835 if (reg == REG_PC)
6836 {
6837 inst.error = _("r15 not allowed in swap");
6838 return;
6839 }
6840
6841 if (skip_past_comma (&str) == FAIL
6842 || *str++ != '[')
6843 {
6844 inst.error = BAD_ARGS;
6845 return;
6846 }
6847
6848 skip_whitespace (str);
6849
6850 if ((reg = reg_required_here (&str, 16)) == FAIL)
6851 return;
6852
6853 if (reg == REG_PC)
6854 {
6855 inst.error = BAD_PC;
6856 return;
6857 }
6858
6859 skip_whitespace (str);
6860
6861 if (*str++ != ']')
6862 {
6863 inst.error = _("missing ]");
6864 return;
6865 }
6866
b99bd4ef
NC
6867 end_of_line (str);
6868 return;
6869}
6870
6871static void
f2b7cb0a 6872do_branch (str)
b99bd4ef 6873 char * str;
b99bd4ef
NC
6874{
6875 if (my_get_expression (&inst.reloc.exp, &str))
6876 return;
6877
6878#ifdef OBJ_ELF
6879 {
6880 char * save_in;
6881
6882 /* ScottB: February 5, 1998 - Check to see of PLT32 reloc
6883 required for the instruction. */
6884
6885 /* arm_parse_reloc () works on input_line_pointer.
6886 We actually want to parse the operands to the branch instruction
6887 passed in 'str'. Save the input pointer and restore it later. */
6888 save_in = input_line_pointer;
6889 input_line_pointer = str;
6890 if (inst.reloc.exp.X_op == O_symbol
6891 && *str == '('
6892 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
6893 {
6894 inst.reloc.type = BFD_RELOC_ARM_PLT32;
6895 inst.reloc.pc_rel = 0;
6896 /* Modify str to point to after parsed operands, otherwise
6897 end_of_line() will complain about the (PLT) left in str. */
6898 str = input_line_pointer;
6899 }
6900 else
6901 {
6902 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
6903 inst.reloc.pc_rel = 1;
6904 }
6905 input_line_pointer = save_in;
6906 }
6907#else
6908 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
6909 inst.reloc.pc_rel = 1;
6910#endif /* OBJ_ELF */
6911
6912 end_of_line (str);
6913 return;
6914}
6915
6916static void
f2b7cb0a 6917do_bx (str)
b99bd4ef 6918 char * str;
b99bd4ef
NC
6919{
6920 int reg;
6921
6922 skip_whitespace (str);
6923
6924 if ((reg = reg_required_here (&str, 0)) == FAIL)
6925 {
6926 inst.error = BAD_ARGS;
6927 return;
6928 }
6929
6930 /* Note - it is not illegal to do a "bx pc". Useless, but not illegal. */
6931 if (reg == REG_PC)
f03698e6 6932 as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
b99bd4ef
NC
6933
6934 end_of_line (str);
6935}
6936
6937static void
f2b7cb0a 6938do_cdp (str)
b99bd4ef 6939 char * str;
b99bd4ef
NC
6940{
6941 /* Co-processor data operation.
6942 Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */
6943 skip_whitespace (str);
6944
6945 if (co_proc_number (&str) == FAIL)
6946 {
6947 if (!inst.error)
6948 inst.error = BAD_ARGS;
6949 return;
6950 }
6951
6952 if (skip_past_comma (&str) == FAIL
6953 || cp_opc_expr (&str, 20,4) == FAIL)
6954 {
6955 if (!inst.error)
6956 inst.error = BAD_ARGS;
6957 return;
6958 }
6959
6960 if (skip_past_comma (&str) == FAIL
6961 || cp_reg_required_here (&str, 12) == FAIL)
6962 {
6963 if (!inst.error)
6964 inst.error = BAD_ARGS;
6965 return;
6966 }
6967
6968 if (skip_past_comma (&str) == FAIL
6969 || cp_reg_required_here (&str, 16) == 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, 0) == FAIL)
6978 {
6979 if (!inst.error)
6980 inst.error = BAD_ARGS;
6981 return;
6982 }
6983
6984 if (skip_past_comma (&str) == SUCCESS)
6985 {
6986 if (cp_opc_expr (&str, 5, 3) == FAIL)
6987 {
6988 if (!inst.error)
6989 inst.error = BAD_ARGS;
6990 return;
6991 }
6992 }
6993
6994 end_of_line (str);
6995 return;
6996}
6997
6998static void
f2b7cb0a 6999do_lstc (str)
b99bd4ef 7000 char * str;
b99bd4ef
NC
7001{
7002 /* Co-processor register load/store.
7003 Format: <LDC|STC{cond}[L] CP#,CRd,<address> */
7004
7005 skip_whitespace (str);
7006
7007 if (co_proc_number (&str) == FAIL)
7008 {
7009 if (!inst.error)
7010 inst.error = BAD_ARGS;
7011 return;
7012 }
7013
7014 if (skip_past_comma (&str) == FAIL
7015 || cp_reg_required_here (&str, 12) == FAIL)
7016 {
7017 if (!inst.error)
7018 inst.error = BAD_ARGS;
7019 return;
7020 }
7021
7022 if (skip_past_comma (&str) == FAIL
bfae80f2 7023 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7024 {
7025 if (! inst.error)
7026 inst.error = BAD_ARGS;
7027 return;
7028 }
7029
b99bd4ef
NC
7030 end_of_line (str);
7031 return;
7032}
7033
7034static void
f2b7cb0a 7035do_co_reg (str)
b99bd4ef 7036 char * str;
b99bd4ef
NC
7037{
7038 /* Co-processor register transfer.
7039 Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */
7040
7041 skip_whitespace (str);
7042
7043 if (co_proc_number (&str) == FAIL)
7044 {
7045 if (!inst.error)
7046 inst.error = BAD_ARGS;
7047 return;
7048 }
7049
7050 if (skip_past_comma (&str) == FAIL
7051 || cp_opc_expr (&str, 21, 3) == FAIL)
7052 {
7053 if (!inst.error)
7054 inst.error = BAD_ARGS;
7055 return;
7056 }
7057
7058 if (skip_past_comma (&str) == FAIL
7059 || reg_required_here (&str, 12) == FAIL)
7060 {
7061 if (!inst.error)
7062 inst.error = BAD_ARGS;
7063 return;
7064 }
7065
7066 if (skip_past_comma (&str) == FAIL
7067 || cp_reg_required_here (&str, 16) == FAIL)
7068 {
7069 if (!inst.error)
7070 inst.error = BAD_ARGS;
7071 return;
7072 }
7073
7074 if (skip_past_comma (&str) == FAIL
7075 || cp_reg_required_here (&str, 0) == FAIL)
7076 {
7077 if (!inst.error)
7078 inst.error = BAD_ARGS;
7079 return;
7080 }
7081
7082 if (skip_past_comma (&str) == SUCCESS)
7083 {
7084 if (cp_opc_expr (&str, 5, 3) == FAIL)
7085 {
7086 if (!inst.error)
7087 inst.error = BAD_ARGS;
7088 return;
7089 }
7090 }
b99bd4ef
NC
7091
7092 end_of_line (str);
7093 return;
7094}
7095
7096static void
f2b7cb0a 7097do_fpa_ctrl (str)
b99bd4ef 7098 char * str;
b99bd4ef
NC
7099{
7100 /* FP control registers.
7101 Format: <WFS|RFS|WFC|RFC>{cond} Rn */
7102
7103 skip_whitespace (str);
7104
7105 if (reg_required_here (&str, 12) == FAIL)
7106 {
7107 if (!inst.error)
7108 inst.error = BAD_ARGS;
7109 return;
7110 }
7111
7112 end_of_line (str);
7113 return;
7114}
7115
7116static void
f2b7cb0a 7117do_fpa_ldst (str)
b99bd4ef 7118 char * str;
b99bd4ef
NC
7119{
7120 skip_whitespace (str);
7121
b99bd4ef
NC
7122 if (fp_reg_required_here (&str, 12) == FAIL)
7123 {
7124 if (!inst.error)
7125 inst.error = BAD_ARGS;
7126 return;
7127 }
7128
7129 if (skip_past_comma (&str) == FAIL
bfae80f2 7130 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7131 {
7132 if (!inst.error)
7133 inst.error = BAD_ARGS;
7134 return;
7135 }
7136
7137 end_of_line (str);
7138}
7139
7140static void
f2b7cb0a 7141do_fpa_ldmstm (str)
b99bd4ef 7142 char * str;
b99bd4ef
NC
7143{
7144 int num_regs;
7145
7146 skip_whitespace (str);
7147
7148 if (fp_reg_required_here (&str, 12) == FAIL)
7149 {
7150 if (! inst.error)
7151 inst.error = BAD_ARGS;
7152 return;
7153 }
7154
7155 /* Get Number of registers to transfer. */
7156 if (skip_past_comma (&str) == FAIL
7157 || my_get_expression (&inst.reloc.exp, &str))
7158 {
7159 if (! inst.error)
7160 inst.error = _("constant expression expected");
7161 return;
7162 }
7163
7164 if (inst.reloc.exp.X_op != O_constant)
7165 {
f03698e6 7166 inst.error = _("constant value required for number of registers");
b99bd4ef
NC
7167 return;
7168 }
7169
7170 num_regs = inst.reloc.exp.X_add_number;
7171
7172 if (num_regs < 1 || num_regs > 4)
7173 {
7174 inst.error = _("number of registers must be in the range [1:4]");
7175 return;
7176 }
7177
7178 switch (num_regs)
7179 {
7180 case 1:
7181 inst.instruction |= CP_T_X;
7182 break;
7183 case 2:
7184 inst.instruction |= CP_T_Y;
7185 break;
7186 case 3:
7187 inst.instruction |= CP_T_Y | CP_T_X;
7188 break;
7189 case 4:
7190 break;
7191 default:
7192 abort ();
7193 }
7194
e28cd48c 7195 if (inst.instruction & (CP_T_Pre | CP_T_UD)) /* ea/fd format. */
b99bd4ef
NC
7196 {
7197 int reg;
7198 int write_back;
7199 int offset;
7200
7201 /* The instruction specified "ea" or "fd", so we can only accept
7202 [Rn]{!}. The instruction does not really support stacking or
7203 unstacking, so we have to emulate these by setting appropriate
7204 bits and offsets. */
7205 if (skip_past_comma (&str) == FAIL
7206 || *str != '[')
7207 {
7208 if (! inst.error)
7209 inst.error = BAD_ARGS;
7210 return;
7211 }
7212
7213 str++;
7214 skip_whitespace (str);
7215
7216 if ((reg = reg_required_here (&str, 16)) == FAIL)
7217 return;
7218
7219 skip_whitespace (str);
7220
7221 if (*str != ']')
7222 {
7223 inst.error = BAD_ARGS;
7224 return;
7225 }
7226
7227 str++;
7228 if (*str == '!')
7229 {
7230 write_back = 1;
7231 str++;
7232 if (reg == REG_PC)
7233 {
7234 inst.error =
f03698e6 7235 _("r15 not allowed as base register with write-back");
b99bd4ef
NC
7236 return;
7237 }
7238 }
7239 else
7240 write_back = 0;
7241
90e4755a 7242 if (inst.instruction & CP_T_Pre)
b99bd4ef
NC
7243 {
7244 /* Pre-decrement. */
7245 offset = 3 * num_regs;
7246 if (write_back)
90e4755a 7247 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7248 }
7249 else
7250 {
7251 /* Post-increment. */
7252 if (write_back)
7253 {
90e4755a 7254 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7255 offset = 3 * num_regs;
7256 }
7257 else
7258 {
7259 /* No write-back, so convert this into a standard pre-increment
7260 instruction -- aesthetically more pleasing. */
90e4755a 7261 inst.instruction |= CP_T_Pre | CP_T_UD;
b99bd4ef
NC
7262 offset = 0;
7263 }
7264 }
7265
f2b7cb0a 7266 inst.instruction |= offset;
b99bd4ef
NC
7267 }
7268 else if (skip_past_comma (&str) == FAIL
bfae80f2 7269 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7270 {
7271 if (! inst.error)
7272 inst.error = BAD_ARGS;
7273 return;
7274 }
7275
7276 end_of_line (str);
7277}
7278
7279static void
f2b7cb0a 7280do_fpa_dyadic (str)
b99bd4ef 7281 char * str;
b99bd4ef
NC
7282{
7283 skip_whitespace (str);
7284
b99bd4ef
NC
7285 if (fp_reg_required_here (&str, 12) == FAIL)
7286 {
7287 if (! inst.error)
7288 inst.error = BAD_ARGS;
7289 return;
7290 }
7291
7292 if (skip_past_comma (&str) == FAIL
7293 || fp_reg_required_here (&str, 16) == FAIL)
7294 {
7295 if (! inst.error)
7296 inst.error = BAD_ARGS;
7297 return;
7298 }
7299
7300 if (skip_past_comma (&str) == FAIL
7301 || fp_op2 (&str) == FAIL)
7302 {
7303 if (! inst.error)
7304 inst.error = BAD_ARGS;
7305 return;
7306 }
7307
b99bd4ef
NC
7308 end_of_line (str);
7309 return;
7310}
7311
7312static void
f2b7cb0a 7313do_fpa_monadic (str)
b99bd4ef 7314 char * str;
b99bd4ef
NC
7315{
7316 skip_whitespace (str);
7317
b99bd4ef
NC
7318 if (fp_reg_required_here (&str, 12) == FAIL)
7319 {
7320 if (! inst.error)
7321 inst.error = BAD_ARGS;
7322 return;
7323 }
7324
7325 if (skip_past_comma (&str) == FAIL
7326 || fp_op2 (&str) == FAIL)
7327 {
7328 if (! inst.error)
7329 inst.error = BAD_ARGS;
7330 return;
7331 }
7332
b99bd4ef
NC
7333 end_of_line (str);
7334 return;
7335}
7336
7337static void
f2b7cb0a 7338do_fpa_cmp (str)
b99bd4ef 7339 char * str;
b99bd4ef
NC
7340{
7341 skip_whitespace (str);
7342
7343 if (fp_reg_required_here (&str, 16) == FAIL)
7344 {
7345 if (! inst.error)
7346 inst.error = BAD_ARGS;
7347 return;
7348 }
7349
7350 if (skip_past_comma (&str) == FAIL
7351 || fp_op2 (&str) == FAIL)
7352 {
7353 if (! inst.error)
7354 inst.error = BAD_ARGS;
7355 return;
7356 }
7357
b99bd4ef
NC
7358 end_of_line (str);
7359 return;
7360}
7361
7362static void
f2b7cb0a 7363do_fpa_from_reg (str)
b99bd4ef 7364 char * str;
b99bd4ef
NC
7365{
7366 skip_whitespace (str);
7367
b99bd4ef
NC
7368 if (fp_reg_required_here (&str, 16) == FAIL)
7369 {
7370 if (! inst.error)
7371 inst.error = BAD_ARGS;
7372 return;
7373 }
7374
7375 if (skip_past_comma (&str) == FAIL
7376 || reg_required_here (&str, 12) == FAIL)
7377 {
7378 if (! inst.error)
7379 inst.error = BAD_ARGS;
7380 return;
7381 }
7382
b99bd4ef
NC
7383 end_of_line (str);
7384 return;
7385}
7386
7387static void
f2b7cb0a 7388do_fpa_to_reg (str)
b99bd4ef 7389 char * str;
b99bd4ef
NC
7390{
7391 skip_whitespace (str);
7392
7393 if (reg_required_here (&str, 12) == FAIL)
7394 return;
7395
7396 if (skip_past_comma (&str) == FAIL
7397 || fp_reg_required_here (&str, 0) == FAIL)
7398 {
7399 if (! inst.error)
7400 inst.error = BAD_ARGS;
7401 return;
7402 }
7403
b99bd4ef
NC
7404 end_of_line (str);
7405 return;
7406}
7407
b99bd4ef 7408static int
bfae80f2
RE
7409vfp_sp_reg_required_here (str, pos)
7410 char **str;
7411 enum vfp_sp_reg_pos pos;
b99bd4ef 7412{
bfae80f2
RE
7413 int reg;
7414 char *start = *str;
b99bd4ef 7415
bfae80f2 7416 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab)) != FAIL)
b99bd4ef 7417 {
bfae80f2 7418 switch (pos)
b99bd4ef 7419 {
bfae80f2
RE
7420 case VFP_REG_Sd:
7421 inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
7422 break;
7423
7424 case VFP_REG_Sn:
7425 inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
7426 break;
7427
7428 case VFP_REG_Sm:
7429 inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
7430 break;
7431
7432 default:
7433 abort ();
b99bd4ef 7434 }
bfae80f2
RE
7435 return reg;
7436 }
b99bd4ef 7437
bfae80f2
RE
7438 /* In the few cases where we might be able to accept something else
7439 this error can be overridden. */
7440 inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
7441
7442 /* Restore the start point. */
7443 *str = start;
7444 return FAIL;
7445}
7446
7447static int
7448vfp_dp_reg_required_here (str, pos)
7449 char **str;
f201ccb3 7450 enum vfp_dp_reg_pos pos;
bfae80f2
RE
7451{
7452 int reg;
7453 char *start = *str;
7454
7455 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL)
7456 {
7457 switch (pos)
b99bd4ef 7458 {
bfae80f2
RE
7459 case VFP_REG_Dd:
7460 inst.instruction |= reg << 12;
7461 break;
b99bd4ef 7462
bfae80f2
RE
7463 case VFP_REG_Dn:
7464 inst.instruction |= reg << 16;
7465 break;
7466
7467 case VFP_REG_Dm:
7468 inst.instruction |= reg << 0;
7469 break;
7470
7471 default:
7472 abort ();
7473 }
7474 return reg;
b99bd4ef
NC
7475 }
7476
bfae80f2
RE
7477 /* In the few cases where we might be able to accept something else
7478 this error can be overridden. */
7479 inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
b99bd4ef 7480
bfae80f2
RE
7481 /* Restore the start point. */
7482 *str = start;
7483 return FAIL;
7484}
b99bd4ef
NC
7485
7486static void
bfae80f2
RE
7487do_vfp_sp_monadic (str)
7488 char *str;
b99bd4ef 7489{
b99bd4ef
NC
7490 skip_whitespace (str);
7491
bfae80f2
RE
7492 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7493 return;
7494
7495 if (skip_past_comma (&str) == FAIL
7496 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef
NC
7497 {
7498 if (! inst.error)
7499 inst.error = BAD_ARGS;
7500 return;
7501 }
7502
bfae80f2
RE
7503 end_of_line (str);
7504 return;
7505}
7506
7507static void
7508do_vfp_dp_monadic (str)
7509 char *str;
7510{
7511 skip_whitespace (str);
7512
7513 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7514 return;
7515
7516 if (skip_past_comma (&str) == FAIL
7517 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
b99bd4ef 7518 {
bfae80f2
RE
7519 if (! inst.error)
7520 inst.error = BAD_ARGS;
7521 return;
b99bd4ef 7522 }
b99bd4ef 7523
bfae80f2
RE
7524 end_of_line (str);
7525 return;
7526}
b99bd4ef 7527
bfae80f2
RE
7528static void
7529do_vfp_sp_dyadic (str)
7530 char *str;
7531{
7532 skip_whitespace (str);
b99bd4ef 7533
bfae80f2
RE
7534 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7535 return;
b99bd4ef 7536
bfae80f2
RE
7537 if (skip_past_comma (&str) == FAIL
7538 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL
7539 || skip_past_comma (&str) == FAIL
7540 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef 7541 {
bfae80f2
RE
7542 if (! inst.error)
7543 inst.error = BAD_ARGS;
7544 return;
7545 }
b99bd4ef 7546
bfae80f2
RE
7547 end_of_line (str);
7548 return;
7549}
b99bd4ef 7550
bfae80f2
RE
7551static void
7552do_vfp_dp_dyadic (str)
7553 char *str;
7554{
7555 skip_whitespace (str);
b99bd4ef 7556
bfae80f2
RE
7557 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7558 return;
b99bd4ef 7559
bfae80f2
RE
7560 if (skip_past_comma (&str) == FAIL
7561 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL
7562 || skip_past_comma (&str) == FAIL
7563 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7564 {
7565 if (! inst.error)
7566 inst.error = BAD_ARGS;
7567 return;
7568 }
b99bd4ef 7569
bfae80f2
RE
7570 end_of_line (str);
7571 return;
7572}
b99bd4ef 7573
bfae80f2
RE
7574static void
7575do_vfp_reg_from_sp (str)
7576 char *str;
7577{
7578 skip_whitespace (str);
7579
7580 if (reg_required_here (&str, 12) == FAIL)
7581 return;
7582
7583 if (skip_past_comma (&str) == FAIL
7584 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7585 {
7586 if (! inst.error)
7587 inst.error = BAD_ARGS;
7588 return;
7589 }
7590
7591 end_of_line (str);
7592 return;
7593}
7594
7595static void
7596do_vfp_sp_reg2 (str)
7597 char *str;
7598{
7599 skip_whitespace (str);
7600
7601 if (reg_required_here (&str, 12) == FAIL)
7602 return;
7603
7604 if (skip_past_comma (&str) == FAIL
7605 || reg_required_here (&str, 16) == FAIL
7606 || skip_past_comma (&str) == FAIL)
7607 {
7608 if (! inst.error)
7609 inst.error = BAD_ARGS;
7610 return;
7611 }
7612
7613 /* We require exactly two consecutive SP registers. */
7614 if (vfp_sp_reg_list (&str, VFP_REG_Sm) != 2)
7615 {
7616 if (! inst.error)
7617 inst.error = _("only two consecutive VFP SP registers allowed here");
7618 }
7619
7620 end_of_line (str);
7621 return;
7622}
7623
7624static void
7625do_vfp_sp_from_reg (str)
7626 char *str;
7627{
7628 skip_whitespace (str);
7629
7630 if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7631 return;
7632
7633 if (skip_past_comma (&str) == FAIL
7634 || reg_required_here (&str, 12) == FAIL)
7635 {
7636 if (! inst.error)
7637 inst.error = BAD_ARGS;
7638 return;
7639 }
7640
7641 end_of_line (str);
7642 return;
7643}
7644
7645static void
7646do_vfp_reg_from_dp (str)
7647 char *str;
7648{
7649 skip_whitespace (str);
7650
7651 if (reg_required_here (&str, 12) == FAIL)
7652 return;
7653
7654 if (skip_past_comma (&str) == FAIL
7655 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
7656 {
7657 if (! inst.error)
7658 inst.error = BAD_ARGS;
7659 return;
7660 }
7661
7662 end_of_line (str);
7663 return;
7664}
7665
7666static void
7667do_vfp_reg2_from_dp (str)
7668 char *str;
7669{
7670 skip_whitespace (str);
7671
7672 if (reg_required_here (&str, 12) == FAIL)
7673 return;
7674
7675 if (skip_past_comma (&str) == FAIL
7676 || reg_required_here (&str, 16) == FAIL
7677 || skip_past_comma (&str) == FAIL
7678 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7679 {
7680 if (! inst.error)
7681 inst.error = BAD_ARGS;
7682 return;
7683 }
7684
7685 end_of_line (str);
7686 return;
7687}
7688
7689static void
7690do_vfp_dp_from_reg (str)
7691 char *str;
7692{
7693 skip_whitespace (str);
7694
7695 if (vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
7696 return;
7697
7698 if (skip_past_comma (&str) == FAIL
7699 || reg_required_here (&str, 12) == FAIL)
7700 {
7701 if (! inst.error)
7702 inst.error = BAD_ARGS;
7703 return;
7704 }
7705
7706 end_of_line (str);
7707 return;
7708}
7709
7710static void
7711do_vfp_dp_from_reg2 (str)
7712 char *str;
7713{
7714 skip_whitespace (str);
7715
7716 if (vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7717 return;
7718
7719 if (skip_past_comma (&str) == FAIL
7720 || reg_required_here (&str, 12) == FAIL
7721 || skip_past_comma (&str) == FAIL
7722 || reg_required_here (&str, 16))
7723 {
7724 if (! inst.error)
7725 inst.error = BAD_ARGS;
7726 return;
7727 }
7728
7729 end_of_line (str);
7730 return;
7731}
7732
7733static const struct vfp_reg *
7734vfp_psr_parse (str)
7735 char **str;
7736{
7737 char *start = *str;
7738 char c;
7739 char *p;
7740 const struct vfp_reg *vreg;
7741
7742 p = start;
7743
7744 /* Find the end of the current token. */
7745 do
7746 {
7747 c = *p++;
7748 }
7749 while (ISALPHA (c));
7750
7751 /* Mark it. */
7752 *--p = 0;
7753
cc8a6dd0 7754 for (vreg = vfp_regs + 0;
bfae80f2
RE
7755 vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg);
7756 vreg++)
7757 {
7758 if (strcmp (start, vreg->name) == 0)
7759 {
7760 *p = c;
7761 *str = p;
7762 return vreg;
7763 }
7764 }
7765
7766 *p = c;
7767 return NULL;
7768}
7769
7770static int
7771vfp_psr_required_here (str)
7772 char **str;
7773{
7774 char *start = *str;
7775 const struct vfp_reg *vreg;
7776
7777 vreg = vfp_psr_parse (str);
7778
7779 if (vreg)
7780 {
7781 inst.instruction |= vreg->regno;
7782 return SUCCESS;
7783 }
7784
7785 inst.error = _("VFP system register expected");
7786
7787 *str = start;
7788 return FAIL;
7789}
7790
7791static void
7792do_vfp_reg_from_ctrl (str)
7793 char *str;
7794{
7795 skip_whitespace (str);
7796
7797 if (reg_required_here (&str, 12) == FAIL)
7798 return;
7799
7800 if (skip_past_comma (&str) == FAIL
7801 || vfp_psr_required_here (&str) == FAIL)
7802 {
7803 if (! inst.error)
7804 inst.error = BAD_ARGS;
7805 return;
7806 }
7807
7808 end_of_line (str);
7809 return;
7810}
7811
7812static void
7813do_vfp_ctrl_from_reg (str)
7814 char *str;
7815{
7816 skip_whitespace (str);
7817
7818 if (vfp_psr_required_here (&str) == FAIL)
7819 return;
7820
7821 if (skip_past_comma (&str) == FAIL
7822 || reg_required_here (&str, 12) == FAIL)
7823 {
7824 if (! inst.error)
7825 inst.error = BAD_ARGS;
7826 return;
7827 }
7828
7829 end_of_line (str);
7830 return;
7831}
7832
7833static void
7834do_vfp_sp_ldst (str)
7835 char *str;
7836{
7837 skip_whitespace (str);
7838
7839 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7840 {
7841 if (!inst.error)
7842 inst.error = BAD_ARGS;
7843 return;
7844 }
7845
7846 if (skip_past_comma (&str) == FAIL
7847 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
7848 {
7849 if (!inst.error)
7850 inst.error = BAD_ARGS;
7851 return;
7852 }
7853
7854 end_of_line (str);
7855 return;
7856}
7857
7858static void
7859do_vfp_dp_ldst (str)
7860 char *str;
7861{
7862 skip_whitespace (str);
7863
7864 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7865 {
7866 if (!inst.error)
7867 inst.error = BAD_ARGS;
7868 return;
7869 }
7870
7871 if (skip_past_comma (&str) == FAIL
7872 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
7873 {
7874 if (!inst.error)
7875 inst.error = BAD_ARGS;
7876 return;
7877 }
7878
7879 end_of_line (str);
7880 return;
7881}
7882
7883/* Parse and encode a VFP SP register list, storing the initial
7884 register in position POS and returning the range as the result. If
7885 the string is invalid return FAIL (an invalid range). */
7886static long
7887vfp_sp_reg_list (str, pos)
7888 char **str;
7889 enum vfp_sp_reg_pos pos;
7890{
7891 long range = 0;
7892 int base_reg = 0;
7893 int new_base;
7894 long base_bits = 0;
7895 int count = 0;
7896 long tempinst;
7897 unsigned long mask = 0;
7898 int warned = 0;
7899
7900 if (**str != '{')
7901 return FAIL;
7902
7903 (*str)++;
7904 skip_whitespace (*str);
7905
7906 tempinst = inst.instruction;
7907
7908 do
7909 {
7910 inst.instruction = 0;
7911
7912 if ((new_base = vfp_sp_reg_required_here (str, pos)) == FAIL)
7913 return FAIL;
7914
7915 if (count == 0 || base_reg > new_base)
7916 {
7917 base_reg = new_base;
7918 base_bits = inst.instruction;
7919 }
7920
7921 if (mask & (1 << new_base))
7922 {
7923 inst.error = _("invalid register list");
7924 return FAIL;
7925 }
7926
7927 if ((mask >> new_base) != 0 && ! warned)
7928 {
7929 as_tsktsk (_("register list not in ascending order"));
7930 warned = 1;
7931 }
7932
7933 mask |= 1 << new_base;
7934 count++;
7935
7936 skip_whitespace (*str);
7937
7938 if (**str == '-') /* We have the start of a range expression */
7939 {
7940 int high_range;
7941
7942 (*str)++;
7943
7944 if ((high_range
7945 = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab))
7946 == FAIL)
7947 {
7948 inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
7949 return FAIL;
7950 }
7951
7952 if (high_range <= new_base)
7953 {
7954 inst.error = _("register range not in ascending order");
7955 return FAIL;
7956 }
7957
7958 for (new_base++; new_base <= high_range; new_base++)
7959 {
7960 if (mask & (1 << new_base))
7961 {
7962 inst.error = _("invalid register list");
7963 return FAIL;
7964 }
7965
7966 mask |= 1 << new_base;
7967 count++;
7968 }
7969 }
7970 }
7971 while (skip_past_comma (str) != FAIL);
7972
7973 if (**str != '}')
7974 {
7975 inst.error = _("invalid register list");
7976 return FAIL;
7977 }
7978
7979 (*str)++;
7980
7981 range = count;
7982
7983 /* Sanity check -- should have raised a parse error above. */
7984 if (count == 0 || count > 32)
c62e1cc3 7985 abort ();
bfae80f2
RE
7986
7987 /* Final test -- the registers must be consecutive. */
7988 while (count--)
7989 {
7990 if ((mask & (1 << base_reg++)) == 0)
7991 {
7992 inst.error = _("non-contiguous register range");
7993 return FAIL;
7994 }
7995 }
7996
7997 inst.instruction = tempinst | base_bits;
7998 return range;
7999}
8000
8001static long
8002vfp_dp_reg_list (str)
8003 char **str;
8004{
8005 long range = 0;
8006 int base_reg = 0;
8007 int new_base;
8008 int count = 0;
8009 long tempinst;
8010 unsigned long mask = 0;
8011 int warned = 0;
8012
8013 if (**str != '{')
8014 return FAIL;
8015
8016 (*str)++;
8017 skip_whitespace (*str);
8018
8019 tempinst = inst.instruction;
8020
8021 do
8022 {
8023 inst.instruction = 0;
8024
8025 if ((new_base = vfp_dp_reg_required_here (str, VFP_REG_Dd)) == FAIL)
8026 return FAIL;
8027
8028 if (count == 0 || base_reg > new_base)
8029 {
8030 base_reg = new_base;
8031 range = inst.instruction;
8032 }
8033
8034 if (mask & (1 << new_base))
8035 {
8036 inst.error = _("invalid register list");
8037 return FAIL;
8038 }
8039
8040 if ((mask >> new_base) != 0 && ! warned)
8041 {
8042 as_tsktsk (_("register list not in ascending order"));
8043 warned = 1;
8044 }
8045
8046 mask |= 1 << new_base;
8047 count++;
8048
8049 skip_whitespace (*str);
8050
8051 if (**str == '-') /* We have the start of a range expression */
8052 {
8053 int high_range;
8054
8055 (*str)++;
8056
8057 if ((high_range
8058 = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab))
8059 == FAIL)
8060 {
8061 inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
8062 return FAIL;
8063 }
8064
8065 if (high_range <= new_base)
8066 {
8067 inst.error = _("register range not in ascending order");
8068 return FAIL;
8069 }
8070
8071 for (new_base++; new_base <= high_range; new_base++)
8072 {
8073 if (mask & (1 << new_base))
8074 {
8075 inst.error = _("invalid register list");
8076 return FAIL;
8077 }
8078
8079 mask |= 1 << new_base;
8080 count++;
8081 }
8082 }
8083 }
8084 while (skip_past_comma (str) != FAIL);
8085
8086 if (**str != '}')
8087 {
8088 inst.error = _("invalid register list");
8089 return FAIL;
8090 }
8091
8092 (*str)++;
8093
8094 range |= 2 * count;
8095
8096 /* Sanity check -- should have raised a parse error above. */
8097 if (count == 0 || count > 16)
c62e1cc3 8098 abort ();
bfae80f2
RE
8099
8100 /* Final test -- the registers must be consecutive. */
8101 while (count--)
8102 {
8103 if ((mask & (1 << base_reg++)) == 0)
8104 {
8105 inst.error = _("non-contiguous register range");
8106 return FAIL;
8107 }
8108 }
8109
8110 inst.instruction = tempinst;
8111 return range;
8112}
8113
8114static void
c62e1cc3 8115vfp_sp_ldstm (str, ldstm_type)
bfae80f2
RE
8116 char *str;
8117 enum vfp_ldstm_type ldstm_type;
8118{
8119 long range;
8120
8121 skip_whitespace (str);
8122
8123 if (reg_required_here (&str, 16) == FAIL)
8124 return;
8125
8126 skip_whitespace (str);
8127
8128 if (*str == '!')
8129 {
8130 inst.instruction |= WRITE_BACK;
8131 str++;
8132 }
8133 else if (ldstm_type != VFP_LDSTMIA)
8134 {
8135 inst.error = _("this addressing mode requires base-register writeback");
8136 return;
8137 }
8138
8139 if (skip_past_comma (&str) == FAIL
8140 || (range = vfp_sp_reg_list (&str, VFP_REG_Sd)) == FAIL)
8141 {
8142 if (!inst.error)
8143 inst.error = BAD_ARGS;
8144 return;
8145 }
8146
8147 inst.instruction |= range;
8148 end_of_line (str);
8149}
8150
8151static void
c62e1cc3 8152vfp_dp_ldstm (str, ldstm_type)
bfae80f2
RE
8153 char *str;
8154 enum vfp_ldstm_type ldstm_type;
8155{
8156 long range;
8157
8158 skip_whitespace (str);
8159
8160 if (reg_required_here (&str, 16) == FAIL)
8161 return;
8162
8163 skip_whitespace (str);
8164
8165 if (*str == '!')
8166 {
8167 inst.instruction |= WRITE_BACK;
8168 str++;
8169 }
8170 else if (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX)
8171 {
8172 inst.error = _("this addressing mode requires base-register writeback");
8173 return;
8174 }
8175
8176 if (skip_past_comma (&str) == FAIL
8177 || (range = vfp_dp_reg_list (&str)) == FAIL)
8178 {
8179 if (!inst.error)
8180 inst.error = BAD_ARGS;
8181 return;
8182 }
8183
8184 if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
8185 range += 1;
8186
8187 inst.instruction |= range;
8188 end_of_line (str);
8189}
8190
8191static void
8192do_vfp_sp_ldstmia (str)
8193 char *str;
8194{
8195 vfp_sp_ldstm (str, VFP_LDSTMIA);
8196}
8197
8198static void
8199do_vfp_sp_ldstmdb (str)
8200 char *str;
8201{
8202 vfp_sp_ldstm (str, VFP_LDSTMDB);
8203}
8204
8205static void
8206do_vfp_dp_ldstmia (str)
8207 char *str;
8208{
8209 vfp_dp_ldstm (str, VFP_LDSTMIA);
8210}
8211
8212static void
8213do_vfp_dp_ldstmdb (str)
8214 char *str;
8215{
8216 vfp_dp_ldstm (str, VFP_LDSTMDB);
8217}
8218
8219static void
8220do_vfp_xp_ldstmia (str)
8221 char *str;
8222{
8223 vfp_dp_ldstm (str, VFP_LDSTMIAX);
8224}
8225
8226static void
8227do_vfp_xp_ldstmdb (str)
8228 char *str;
8229{
8230 vfp_dp_ldstm (str, VFP_LDSTMDBX);
8231}
8232
8233static void
8234do_vfp_sp_compare_z (str)
8235 char *str;
8236{
8237 skip_whitespace (str);
8238
8239 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8240 {
8241 if (!inst.error)
8242 inst.error = BAD_ARGS;
8243 return;
8244 }
8245
8246 end_of_line (str);
8247 return;
8248}
8249
8250static void
8251do_vfp_dp_compare_z (str)
8252 char *str;
8253{
8254 skip_whitespace (str);
8255
8256 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8257 {
8258 if (!inst.error)
8259 inst.error = BAD_ARGS;
8260 return;
8261 }
8262
8263 end_of_line (str);
8264 return;
8265}
8266
8267static void
8268do_vfp_dp_sp_cvt (str)
8269 char *str;
8270{
8271 skip_whitespace (str);
8272
8273 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8274 return;
8275
8276 if (skip_past_comma (&str) == FAIL
8277 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
8278 {
8279 if (! inst.error)
8280 inst.error = BAD_ARGS;
8281 return;
8282 }
8283
8284 end_of_line (str);
8285 return;
8286}
8287
8288static void
8289do_vfp_sp_dp_cvt (str)
8290 char *str;
8291{
8292 skip_whitespace (str);
8293
8294 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8295 return;
8296
8297 if (skip_past_comma (&str) == FAIL
8298 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8299 {
8300 if (! inst.error)
8301 inst.error = BAD_ARGS;
8302 return;
8303 }
8304
8305 end_of_line (str);
8306 return;
8307}
8308
8309/* Thumb specific routines. */
8310
8311/* Parse and validate that a register is of the right form, this saves
8312 repeated checking of this information in many similar cases.
8313 Unlike the 32-bit case we do not insert the register into the opcode
8314 here, since the position is often unknown until the full instruction
8315 has been parsed. */
8316
8317static int
8318thumb_reg (strp, hi_lo)
8319 char ** strp;
8320 int hi_lo;
8321{
8322 int reg;
8323
8324 if ((reg = reg_required_here (strp, -1)) == FAIL)
8325 return FAIL;
8326
8327 switch (hi_lo)
8328 {
8329 case THUMB_REG_LO:
8330 if (reg > 7)
8331 {
8332 inst.error = _("lo register required");
8333 return FAIL;
8334 }
8335 break;
8336
8337 case THUMB_REG_HI:
8338 if (reg < 8)
8339 {
8340 inst.error = _("hi register required");
8341 return FAIL;
8342 }
8343 break;
8344
8345 default:
8346 break;
8347 }
8348
8349 return reg;
8350}
8351
8352/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
8353 was SUB. */
8354
8355static void
8356thumb_add_sub (str, subtract)
8357 char * str;
8358 int subtract;
8359{
8360 int Rd, Rs, Rn = FAIL;
8361
8362 skip_whitespace (str);
8363
8364 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
8365 || skip_past_comma (&str) == FAIL)
8366 {
8367 if (! inst.error)
8368 inst.error = BAD_ARGS;
8369 return;
8370 }
8371
8372 if (is_immediate_prefix (*str))
8373 {
8374 Rs = Rd;
8375 str++;
8376 if (my_get_expression (&inst.reloc.exp, &str))
8377 return;
8378 }
8379 else
8380 {
8381 if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8382 return;
8383
8384 if (skip_past_comma (&str) == FAIL)
8385 {
8386 /* Two operand format, shuffle the registers
8387 and pretend there are 3. */
8388 Rn = Rs;
8389 Rs = Rd;
8390 }
8391 else if (is_immediate_prefix (*str))
8392 {
8393 str++;
8394 if (my_get_expression (&inst.reloc.exp, &str))
8395 return;
8396 }
8397 else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8398 return;
8399 }
8400
8401 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8402 for the latter case, EXPR contains the immediate that was found. */
8403 if (Rn != FAIL)
8404 {
8405 /* All register format. */
8406 if (Rd > 7 || Rs > 7 || Rn > 7)
8407 {
8408 if (Rs != Rd)
8409 {
8410 inst.error = _("dest and source1 must be the same register");
8411 return;
8412 }
8413
8414 /* Can't do this for SUB. */
8415 if (subtract)
8416 {
8417 inst.error = _("subtract valid only on lo regs");
8418 return;
8419 }
8420
8421 inst.instruction = (T_OPCODE_ADD_HI
8422 | (Rd > 7 ? THUMB_H1 : 0)
8423 | (Rn > 7 ? THUMB_H2 : 0));
8424 inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
8425 }
8426 else
8427 {
8428 inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
8429 inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8430 }
8431 }
8432 else
8433 {
8434 /* Immediate expression, now things start to get nasty. */
8435
8436 /* First deal with HI regs, only very restricted cases allowed:
8437 Adjusting SP, and using PC or SP to get an address. */
8438 if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8439 || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
8440 {
8441 inst.error = _("invalid Hi register with immediate");
8442 return;
8443 }
8444
8445 if (inst.reloc.exp.X_op != O_constant)
8446 {
8447 /* Value isn't known yet, all we can do is store all the fragments
8448 we know about in the instruction and let the reloc hacking
8449 work it all out. */
8450 inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
8451 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8452 }
8453 else
8454 {
8455 int offset = inst.reloc.exp.X_add_number;
8456
8457 if (subtract)
358b94bd 8458 offset = - offset;
bfae80f2
RE
8459
8460 if (offset < 0)
8461 {
358b94bd 8462 offset = - offset;
bfae80f2
RE
8463 subtract = 1;
8464
8465 /* Quick check, in case offset is MIN_INT. */
8466 if (offset < 0)
8467 {
8468 inst.error = _("immediate value out of range");
8469 return;
8470 }
8471 }
358b94bd
NC
8472 /* Note - you cannot convert a subtract of 0 into an
8473 add of 0 because the carry flag is set differently. */
8474 else if (offset > 0)
bfae80f2
RE
8475 subtract = 0;
8476
8477 if (Rd == REG_SP)
8478 {
8479 if (offset & ~0x1fc)
8480 {
8481 inst.error = _("invalid immediate value for stack adjust");
8482 return;
b99bd4ef
NC
8483 }
8484 inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
8485 inst.instruction |= offset >> 2;
8486 }
8487 else if (Rs == REG_PC || Rs == REG_SP)
8488 {
8489 if (subtract
8490 || (offset & ~0x3fc))
8491 {
8492 inst.error = _("invalid immediate for address calculation");
8493 return;
8494 }
8495 inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
8496 : T_OPCODE_ADD_SP);
8497 inst.instruction |= (Rd << 8) | (offset >> 2);
8498 }
8499 else if (Rs == Rd)
8500 {
8501 if (offset & ~0xff)
8502 {
8503 inst.error = _("immediate value out of range");
8504 return;
8505 }
8506 inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
8507 inst.instruction |= (Rd << 8) | offset;
8508 }
8509 else
8510 {
8511 if (offset & ~0x7)
8512 {
8513 inst.error = _("immediate value out of range");
8514 return;
8515 }
8516 inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
8517 inst.instruction |= Rd | (Rs << 3) | (offset << 6);
8518 }
8519 }
8520 }
8521
8522 end_of_line (str);
8523}
8524
8525static void
8526thumb_shift (str, shift)
8527 char * str;
8528 int shift;
8529{
8530 int Rd, Rs, Rn = FAIL;
8531
8532 skip_whitespace (str);
8533
8534 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8535 || skip_past_comma (&str) == FAIL)
8536 {
8537 if (! inst.error)
8538 inst.error = BAD_ARGS;
8539 return;
8540 }
8541
8542 if (is_immediate_prefix (*str))
8543 {
8544 /* Two operand immediate format, set Rs to Rd. */
8545 Rs = Rd;
8546 str ++;
8547 if (my_get_expression (&inst.reloc.exp, &str))
8548 return;
8549 }
8550 else
8551 {
8552 if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8553 return;
8554
8555 if (skip_past_comma (&str) == FAIL)
8556 {
8557 /* Two operand format, shuffle the registers
8558 and pretend there are 3. */
8559 Rn = Rs;
8560 Rs = Rd;
8561 }
8562 else if (is_immediate_prefix (*str))
8563 {
8564 str++;
8565 if (my_get_expression (&inst.reloc.exp, &str))
8566 return;
8567 }
8568 else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8569 return;
8570 }
8571
8572 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8573 for the latter case, EXPR contains the immediate that was found. */
8574
8575 if (Rn != FAIL)
8576 {
8577 if (Rs != Rd)
8578 {
8579 inst.error = _("source1 and dest must be same register");
8580 return;
8581 }
8582
8583 switch (shift)
8584 {
8585 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
8586 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
8587 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
8588 }
8589
8590 inst.instruction |= Rd | (Rn << 3);
8591 }
8592 else
8593 {
8594 switch (shift)
8595 {
8596 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
8597 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
8598 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
8599 }
8600
8601 if (inst.reloc.exp.X_op != O_constant)
8602 {
8603 /* Value isn't known yet, create a dummy reloc and let reloc
8604 hacking fix it up. */
8605 inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
8606 }
8607 else
8608 {
8609 unsigned shift_value = inst.reloc.exp.X_add_number;
8610
8611 if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
8612 {
f03698e6 8613 inst.error = _("invalid immediate for shift");
b99bd4ef
NC
8614 return;
8615 }
8616
8617 /* Shifts of zero are handled by converting to LSL. */
8618 if (shift_value == 0)
8619 inst.instruction = T_OPCODE_LSL_I;
8620
8621 /* Shifts of 32 are encoded as a shift of zero. */
8622 if (shift_value == 32)
8623 shift_value = 0;
8624
8625 inst.instruction |= shift_value << 6;
8626 }
8627
8628 inst.instruction |= Rd | (Rs << 3);
8629 }
8630
8631 end_of_line (str);
8632}
8633
8634static void
8635thumb_mov_compare (str, move)
8636 char * str;
8637 int move;
8638{
8639 int Rd, Rs = FAIL;
8640
8641 skip_whitespace (str);
8642
8643 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
8644 || skip_past_comma (&str) == FAIL)
8645 {
8646 if (! inst.error)
8647 inst.error = BAD_ARGS;
8648 return;
8649 }
8650
8651 if (is_immediate_prefix (*str))
8652 {
8653 str++;
8654 if (my_get_expression (&inst.reloc.exp, &str))
8655 return;
8656 }
8657 else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8658 return;
8659
8660 if (Rs != FAIL)
8661 {
8662 if (Rs < 8 && Rd < 8)
8663 {
8664 if (move == THUMB_MOVE)
8665 /* A move of two lowregs is encoded as ADD Rd, Rs, #0
8666 since a MOV instruction produces unpredictable results. */
8667 inst.instruction = T_OPCODE_ADD_I3;
8668 else
8669 inst.instruction = T_OPCODE_CMP_LR;
8670 inst.instruction |= Rd | (Rs << 3);
8671 }
8672 else
8673 {
8674 if (move == THUMB_MOVE)
8675 inst.instruction = T_OPCODE_MOV_HR;
8676 else
8677 inst.instruction = T_OPCODE_CMP_HR;
8678
8679 if (Rd > 7)
8680 inst.instruction |= THUMB_H1;
8681
8682 if (Rs > 7)
8683 inst.instruction |= THUMB_H2;
8684
8685 inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
8686 }
8687 }
8688 else
8689 {
8690 if (Rd > 7)
8691 {
8692 inst.error = _("only lo regs allowed with immediate");
8693 return;
8694 }
8695
8696 if (move == THUMB_MOVE)
8697 inst.instruction = T_OPCODE_MOV_I8;
8698 else
8699 inst.instruction = T_OPCODE_CMP_I8;
8700
8701 inst.instruction |= Rd << 8;
8702
8703 if (inst.reloc.exp.X_op != O_constant)
8704 inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
8705 else
8706 {
8707 unsigned value = inst.reloc.exp.X_add_number;
8708
8709 if (value > 255)
8710 {
8711 inst.error = _("invalid immediate");
8712 return;
8713 }
8714
8715 inst.instruction |= value;
8716 }
8717 }
8718
8719 end_of_line (str);
8720}
8721
8722static void
8723thumb_load_store (str, load_store, size)
8724 char * str;
8725 int load_store;
8726 int size;
8727{
8728 int Rd, Rb, Ro = FAIL;
8729
8730 skip_whitespace (str);
8731
8732 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8733 || skip_past_comma (&str) == FAIL)
8734 {
8735 if (! inst.error)
8736 inst.error = BAD_ARGS;
8737 return;
8738 }
8739
8740 if (*str == '[')
8741 {
8742 str++;
8743 if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8744 return;
8745
8746 if (skip_past_comma (&str) != FAIL)
8747 {
8748 if (is_immediate_prefix (*str))
8749 {
8750 str++;
8751 if (my_get_expression (&inst.reloc.exp, &str))
8752 return;
8753 }
8754 else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8755 return;
8756 }
8757 else
8758 {
8759 inst.reloc.exp.X_op = O_constant;
8760 inst.reloc.exp.X_add_number = 0;
8761 }
8762
8763 if (*str != ']')
8764 {
8765 inst.error = _("expected ']'");
8766 return;
8767 }
8768 str++;
8769 }
8770 else if (*str == '=')
8771 {
f03698e6
RE
8772 if (load_store != THUMB_LOAD)
8773 {
8774 inst.error = _("invalid pseudo operation");
8775 return;
8776 }
8777
b99bd4ef
NC
8778 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
8779 str++;
8780
8781 skip_whitespace (str);
8782
8783 if (my_get_expression (& inst.reloc.exp, & str))
8784 return;
8785
8786 end_of_line (str);
8787
8788 if ( inst.reloc.exp.X_op != O_constant
8789 && inst.reloc.exp.X_op != O_symbol)
8790 {
8791 inst.error = "Constant expression expected";
8792 return;
8793 }
8794
8795 if (inst.reloc.exp.X_op == O_constant
8796 && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
8797 {
8798 /* This can be done with a mov instruction. */
8799
8800 inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8);
8801 inst.instruction |= inst.reloc.exp.X_add_number;
8802 return;
8803 }
8804
8805 /* Insert into literal pool. */
8806 if (add_to_lit_pool () == FAIL)
8807 {
8808 if (!inst.error)
8809 inst.error = "literal pool insertion failed";
8810 return;
8811 }
8812
8813 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8814 inst.reloc.pc_rel = 1;
8815 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8816 /* Adjust ARM pipeline offset to Thumb. */
8817 inst.reloc.exp.X_add_number += 4;
8818
8819 return;
8820 }
8821 else
8822 {
8823 if (my_get_expression (&inst.reloc.exp, &str))
8824 return;
8825
8826 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8827 inst.reloc.pc_rel = 1;
8828 inst.reloc.exp.X_add_number -= 4; /* Pipeline offset. */
8829 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8830 end_of_line (str);
8831 return;
8832 }
8833
8834 if (Rb == REG_PC || Rb == REG_SP)
8835 {
8836 if (size != THUMB_WORD)
8837 {
8838 inst.error = _("byte or halfword not valid for base register");
8839 return;
8840 }
8841 else if (Rb == REG_PC && load_store != THUMB_LOAD)
8842 {
f03698e6 8843 inst.error = _("r15 based store not allowed");
b99bd4ef
NC
8844 return;
8845 }
8846 else if (Ro != FAIL)
8847 {
f03698e6 8848 inst.error = _("invalid base register for register offset");
b99bd4ef
NC
8849 return;
8850 }
8851
8852 if (Rb == REG_PC)
8853 inst.instruction = T_OPCODE_LDR_PC;
8854 else if (load_store == THUMB_LOAD)
8855 inst.instruction = T_OPCODE_LDR_SP;
8856 else
8857 inst.instruction = T_OPCODE_STR_SP;
8858
8859 inst.instruction |= Rd << 8;
8860 if (inst.reloc.exp.X_op == O_constant)
8861 {
8862 unsigned offset = inst.reloc.exp.X_add_number;
8863
8864 if (offset & ~0x3fc)
8865 {
8866 inst.error = _("invalid offset");
8867 return;
8868 }
8869
8870 inst.instruction |= offset >> 2;
8871 }
8872 else
8873 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8874 }
8875 else if (Rb > 7)
8876 {
8877 inst.error = _("invalid base register in load/store");
8878 return;
8879 }
8880 else if (Ro == FAIL)
8881 {
8882 /* Immediate offset. */
8883 if (size == THUMB_WORD)
8884 inst.instruction = (load_store == THUMB_LOAD
8885 ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
8886 else if (size == THUMB_HALFWORD)
8887 inst.instruction = (load_store == THUMB_LOAD
8888 ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
8889 else
8890 inst.instruction = (load_store == THUMB_LOAD
8891 ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
8892
8893 inst.instruction |= Rd | (Rb << 3);
8894
8895 if (inst.reloc.exp.X_op == O_constant)
8896 {
8897 unsigned offset = inst.reloc.exp.X_add_number;
8898
8899 if (offset & ~(0x1f << size))
8900 {
f03698e6 8901 inst.error = _("invalid offset");
b99bd4ef
NC
8902 return;
8903 }
8904 inst.instruction |= (offset >> size) << 6;
8905 }
8906 else
8907 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8908 }
8909 else
8910 {
8911 /* Register offset. */
8912 if (size == THUMB_WORD)
8913 inst.instruction = (load_store == THUMB_LOAD
8914 ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
8915 else if (size == THUMB_HALFWORD)
8916 inst.instruction = (load_store == THUMB_LOAD
8917 ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
8918 else
8919 inst.instruction = (load_store == THUMB_LOAD
8920 ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
8921
8922 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
8923 }
8924
8925 end_of_line (str);
8926}
8927
404ff6b5
AH
8928/* A register must be given at this point.
8929
404ff6b5
AH
8930 Shift is the place to put it in inst.instruction.
8931
404ff6b5
AH
8932 Restores input start point on err.
8933 Returns the reg#, or FAIL. */
8934
8935static int
63e63b07 8936mav_reg_required_here (str, shift, regtype)
404ff6b5
AH
8937 char ** str;
8938 int shift;
6c43fab6 8939 enum arm_reg_type regtype;
404ff6b5 8940{
6c43fab6
RE
8941 int reg;
8942 char *start = *str;
404ff6b5 8943
6c43fab6 8944 if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL)
404ff6b5 8945 {
404ff6b5
AH
8946 if (shift >= 0)
8947 inst.instruction |= reg << shift;
8948
6c43fab6 8949 return reg;
404ff6b5
AH
8950 }
8951
6c43fab6 8952 /* Restore the start point. */
404ff6b5 8953 *str = start;
cc8a6dd0 8954
404ff6b5
AH
8955 /* In the few cases where we might be able to accept something else
8956 this error can be overridden. */
6c43fab6 8957 inst.error = _(all_reg_maps[regtype].expected);
cc8a6dd0 8958
404ff6b5
AH
8959 return FAIL;
8960}
8961
63e63b07 8962/* Cirrus Maverick Instructions. */
404ff6b5
AH
8963
8964/* Wrapper functions. */
8965
8966static void
63e63b07 8967do_mav_binops_1a (str)
6c43fab6
RE
8968 char * str;
8969{
63e63b07 8970 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF);
6c43fab6
RE
8971}
8972
8973static void
63e63b07 8974do_mav_binops_1b (str)
6c43fab6
RE
8975 char * str;
8976{
63e63b07 8977 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD);
6c43fab6
RE
8978}
8979
8980static void
63e63b07 8981do_mav_binops_1c (str)
404ff6b5 8982 char * str;
404ff6b5 8983{
63e63b07 8984 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX);
404ff6b5
AH
8985}
8986
8987static void
63e63b07 8988do_mav_binops_1d (str)
404ff6b5 8989 char * str;
404ff6b5 8990{
63e63b07 8991 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF);
404ff6b5
AH
8992}
8993
8994static void
63e63b07 8995do_mav_binops_1e (str)
404ff6b5 8996 char * str;
404ff6b5 8997{
63e63b07 8998 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD);
404ff6b5
AH
8999}
9000
9001static void
63e63b07 9002do_mav_binops_1f (str)
404ff6b5 9003 char * str;
404ff6b5 9004{
63e63b07 9005 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF);
404ff6b5
AH
9006}
9007
9008static void
63e63b07 9009do_mav_binops_1g (str)
404ff6b5 9010 char * str;
404ff6b5 9011{
63e63b07 9012 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD);
404ff6b5
AH
9013}
9014
9015static void
63e63b07 9016do_mav_binops_1h (str)
404ff6b5 9017 char * str;
404ff6b5 9018{
63e63b07 9019 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX);
404ff6b5
AH
9020}
9021
6c43fab6 9022static void
63e63b07 9023do_mav_binops_1i (str)
6c43fab6
RE
9024 char * str;
9025{
63e63b07 9026 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX);
6c43fab6
RE
9027}
9028
9029static void
63e63b07 9030do_mav_binops_1j (str)
6c43fab6
RE
9031 char * str;
9032{
63e63b07 9033 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX);
6c43fab6
RE
9034}
9035
9036static void
63e63b07 9037do_mav_binops_1k (str)
6c43fab6
RE
9038 char * str;
9039{
63e63b07 9040 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX);
6c43fab6
RE
9041}
9042
9043static void
63e63b07 9044do_mav_binops_1l (str)
6c43fab6
RE
9045 char * str;
9046{
63e63b07 9047 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF);
6c43fab6
RE
9048}
9049
9050static void
63e63b07 9051do_mav_binops_1m (str)
6c43fab6
RE
9052 char * str;
9053{
63e63b07 9054 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD);
6c43fab6
RE
9055}
9056
9057static void
63e63b07 9058do_mav_binops_1n (str)
6c43fab6
RE
9059 char * str;
9060{
63e63b07 9061 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9062}
9063
9064static void
63e63b07 9065do_mav_binops_1o (str)
6c43fab6
RE
9066 char * str;
9067{
63e63b07 9068 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9069}
9070
9071static void
63e63b07 9072do_mav_binops_2a (str)
6c43fab6
RE
9073 char * str;
9074{
63e63b07 9075 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN);
6c43fab6
RE
9076}
9077
9078static void
63e63b07 9079do_mav_binops_2b (str)
6c43fab6
RE
9080 char * str;
9081{
63e63b07 9082 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN);
6c43fab6
RE
9083}
9084
9085static void
63e63b07 9086do_mav_binops_2c (str)
6c43fab6
RE
9087 char * str;
9088{
63e63b07 9089 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN);
6c43fab6
RE
9090}
9091
9092static void
63e63b07 9093do_mav_binops_3a (str)
6c43fab6
RE
9094 char * str;
9095{
63e63b07 9096 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX);
6c43fab6
RE
9097}
9098
9099static void
63e63b07 9100do_mav_binops_3b (str)
6c43fab6
RE
9101 char * str;
9102{
63e63b07 9103 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX);
6c43fab6
RE
9104}
9105
9106static void
63e63b07 9107do_mav_binops_3c (str)
6c43fab6
RE
9108 char * str;
9109{
63e63b07 9110 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX);
6c43fab6
RE
9111}
9112
9113static void
63e63b07 9114do_mav_binops_3d (str)
6c43fab6
RE
9115 char * str;
9116{
63e63b07 9117 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX);
6c43fab6
RE
9118}
9119
9120static void
63e63b07 9121do_mav_triple_4a (str)
6c43fab6
RE
9122 char * str;
9123{
63e63b07 9124 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN);
6c43fab6
RE
9125}
9126
9127static void
63e63b07 9128do_mav_triple_4b (str)
6c43fab6
RE
9129 char * str;
9130{
63e63b07 9131 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN);
6c43fab6
RE
9132}
9133
9134static void
63e63b07 9135do_mav_triple_5a (str)
6c43fab6
RE
9136 char * str;
9137{
63e63b07 9138 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF);
6c43fab6
RE
9139}
9140
9141static void
63e63b07 9142do_mav_triple_5b (str)
6c43fab6
RE
9143 char * str;
9144{
63e63b07 9145 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD);
6c43fab6
RE
9146}
9147
9148static void
63e63b07 9149do_mav_triple_5c (str)
6c43fab6
RE
9150 char * str;
9151{
63e63b07 9152 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9153}
9154
9155static void
63e63b07 9156do_mav_triple_5d (str)
6c43fab6
RE
9157 char * str;
9158{
63e63b07 9159 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9160}
9161
9162static void
63e63b07 9163do_mav_triple_5e (str)
6c43fab6
RE
9164 char * str;
9165{
63e63b07 9166 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF);
6c43fab6
RE
9167}
9168
9169static void
63e63b07 9170do_mav_triple_5f (str)
6c43fab6
RE
9171 char * str;
9172{
63e63b07 9173 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD);
6c43fab6
RE
9174}
9175
9176static void
63e63b07 9177do_mav_triple_5g (str)
6c43fab6
RE
9178 char * str;
9179{
63e63b07 9180 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9181}
9182
9183static void
63e63b07 9184do_mav_triple_5h (str)
6c43fab6
RE
9185 char * str;
9186{
63e63b07 9187 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9188}
9189
9190static void
63e63b07 9191do_mav_quad_6a (str)
6c43fab6
RE
9192 char * str;
9193{
63e63b07 9194 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX,
6c43fab6
RE
9195 REG_TYPE_MVFX);
9196}
9197
9198static void
63e63b07 9199do_mav_quad_6b (str)
6c43fab6
RE
9200 char * str;
9201{
63e63b07 9202 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX,
6c43fab6
RE
9203 REG_TYPE_MVFX);
9204}
9205
cc8a6dd0 9206/* cfmvsc32<cond> DSPSC,MVFX[15:0]. */
404ff6b5 9207static void
63e63b07 9208do_mav_dspsc_1 (str)
404ff6b5 9209 char * str;
404ff6b5 9210{
6c43fab6
RE
9211 skip_whitespace (str);
9212
9213 /* cfmvsc32. */
63e63b07 9214 if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL
6c43fab6 9215 || skip_past_comma (&str) == FAIL
63e63b07 9216 || mav_reg_required_here (&str, 16, REG_TYPE_MVFX) == FAIL)
6c43fab6
RE
9217 {
9218 if (!inst.error)
9219 inst.error = BAD_ARGS;
9220
9221 return;
9222 }
9223
9224 end_of_line (str);
404ff6b5
AH
9225}
9226
6c43fab6 9227/* cfmv32sc<cond> MVFX[15:0],DSPSC. */
404ff6b5 9228static void
63e63b07 9229do_mav_dspsc_2 (str)
404ff6b5 9230 char * str;
404ff6b5 9231{
6c43fab6
RE
9232 skip_whitespace (str);
9233
9234 /* cfmv32sc. */
63e63b07 9235 if (mav_reg_required_here (&str, 0, REG_TYPE_MVFX) == FAIL
6c43fab6 9236 || skip_past_comma (&str) == FAIL
63e63b07 9237 || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL)
6c43fab6
RE
9238 {
9239 if (!inst.error)
9240 inst.error = BAD_ARGS;
9241
9242 return;
9243 }
9244
9245 end_of_line (str);
404ff6b5
AH
9246}
9247
9248static void
63e63b07 9249do_mav_shift_1 (str)
404ff6b5 9250 char * str;
404ff6b5 9251{
63e63b07 9252 do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX);
404ff6b5
AH
9253}
9254
9255static void
63e63b07 9256do_mav_shift_2 (str)
404ff6b5 9257 char * str;
404ff6b5 9258{
63e63b07 9259 do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX);
404ff6b5
AH
9260}
9261
9262static void
63e63b07 9263do_mav_ldst_1 (str)
404ff6b5 9264 char * str;
404ff6b5 9265{
63e63b07 9266 do_mav_ldst (str, REG_TYPE_MVF);
404ff6b5
AH
9267}
9268
9269static void
63e63b07 9270do_mav_ldst_2 (str)
404ff6b5 9271 char * str;
404ff6b5 9272{
63e63b07 9273 do_mav_ldst (str, REG_TYPE_MVD);
404ff6b5
AH
9274}
9275
9276static void
63e63b07 9277do_mav_ldst_3 (str)
404ff6b5 9278 char * str;
404ff6b5 9279{
63e63b07 9280 do_mav_ldst (str, REG_TYPE_MVFX);
404ff6b5
AH
9281}
9282
9283static void
63e63b07 9284do_mav_ldst_4 (str)
404ff6b5 9285 char * str;
404ff6b5 9286{
63e63b07 9287 do_mav_ldst (str, REG_TYPE_MVDX);
404ff6b5
AH
9288}
9289
9290/* Isnsn like "foo X,Y". */
9291
9292static void
63e63b07 9293do_mav_binops (str, mode, reg0, reg1)
404ff6b5 9294 char * str;
404ff6b5 9295 int mode;
6c43fab6
RE
9296 enum arm_reg_type reg0;
9297 enum arm_reg_type reg1;
404ff6b5 9298{
6c43fab6 9299 int shift0, shift1;
404ff6b5 9300
6c43fab6
RE
9301 shift0 = mode & 0xff;
9302 shift1 = (mode >> 8) & 0xff;
404ff6b5
AH
9303
9304 skip_whitespace (str);
9305
63e63b07 9306 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
404ff6b5 9307 || skip_past_comma (&str) == FAIL
63e63b07 9308 || mav_reg_required_here (&str, shift1, reg1) == FAIL)
404ff6b5
AH
9309 {
9310 if (!inst.error)
9311 inst.error = BAD_ARGS;
9312 }
9313 else
9314 end_of_line (str);
404ff6b5
AH
9315}
9316
9317/* Isnsn like "foo X,Y,Z". */
9318
9319static void
63e63b07 9320do_mav_triple (str, mode, reg0, reg1, reg2)
404ff6b5 9321 char * str;
404ff6b5 9322 int mode;
6c43fab6
RE
9323 enum arm_reg_type reg0;
9324 enum arm_reg_type reg1;
9325 enum arm_reg_type reg2;
404ff6b5 9326{
6c43fab6 9327 int shift0, shift1, shift2;
404ff6b5 9328
6c43fab6
RE
9329 shift0 = mode & 0xff;
9330 shift1 = (mode >> 8) & 0xff;
9331 shift2 = (mode >> 16) & 0xff;
404ff6b5
AH
9332
9333 skip_whitespace (str);
9334
63e63b07 9335 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
404ff6b5 9336 || skip_past_comma (&str) == FAIL
63e63b07 9337 || mav_reg_required_here (&str, shift1, reg1) == FAIL
404ff6b5 9338 || skip_past_comma (&str) == FAIL
63e63b07 9339 || mav_reg_required_here (&str, shift2, reg2) == FAIL)
404ff6b5
AH
9340 {
9341 if (!inst.error)
9342 inst.error = BAD_ARGS;
9343 }
9344 else
9345 end_of_line (str);
404ff6b5
AH
9346}
9347
9348/* Isnsn like "foo W,X,Y,Z".
9349 where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */
9350
9351static void
63e63b07 9352do_mav_quad (str, mode, reg0, reg1, reg2, reg3)
404ff6b5 9353 char * str;
404ff6b5 9354 int mode;
6c43fab6
RE
9355 enum arm_reg_type reg0;
9356 enum arm_reg_type reg1;
9357 enum arm_reg_type reg2;
9358 enum arm_reg_type reg3;
404ff6b5 9359{
6c43fab6 9360 int shift0, shift1, shift2, shift3;
404ff6b5 9361
6c43fab6
RE
9362 shift0= mode & 0xff;
9363 shift1 = (mode >> 8) & 0xff;
9364 shift2 = (mode >> 16) & 0xff;
9365 shift3 = (mode >> 24) & 0xff;
404ff6b5
AH
9366
9367 skip_whitespace (str);
9368
63e63b07 9369 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
404ff6b5 9370 || skip_past_comma (&str) == FAIL
63e63b07 9371 || mav_reg_required_here (&str, shift1, reg1) == FAIL
404ff6b5 9372 || skip_past_comma (&str) == FAIL
63e63b07 9373 || mav_reg_required_here (&str, shift2, reg2) == FAIL
404ff6b5 9374 || skip_past_comma (&str) == FAIL
63e63b07 9375 || mav_reg_required_here (&str, shift3, reg3) == FAIL)
404ff6b5
AH
9376 {
9377 if (!inst.error)
9378 inst.error = BAD_ARGS;
9379 }
9380 else
9381 end_of_line (str);
404ff6b5
AH
9382}
9383
63e63b07 9384/* Maverick shift immediate instructions.
404ff6b5
AH
9385 cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
9386 cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */
9387
9388static void
63e63b07 9389do_mav_shift (str, reg0, reg1)
404ff6b5 9390 char * str;
6c43fab6
RE
9391 enum arm_reg_type reg0;
9392 enum arm_reg_type reg1;
404ff6b5
AH
9393{
9394 int error;
9395 int imm, neg = 0;
9396
9397 skip_whitespace (str);
9398
9399 error = 0;
9400
63e63b07 9401 if (mav_reg_required_here (&str, 12, reg0) == FAIL
404ff6b5 9402 || skip_past_comma (&str) == FAIL
63e63b07 9403 || mav_reg_required_here (&str, 16, reg1) == FAIL
404ff6b5
AH
9404 || skip_past_comma (&str) == FAIL)
9405 {
9406 if (!inst.error)
9407 inst.error = BAD_ARGS;
9408 return;
9409 }
9410
9411 /* Calculate the immediate operand.
9412 The operand is a 7bit signed number. */
9413 skip_whitespace (str);
9414
9415 if (*str == '#')
9416 ++str;
9417
8420dfca 9418 if (!ISDIGIT (*str) && *str != '-')
404ff6b5
AH
9419 {
9420 inst.error = _("expecting immediate, 7bit operand");
9421 return;
9422 }
9423
9424 if (*str == '-')
9425 {
9426 neg = 1;
9427 ++str;
9428 }
9429
8420dfca 9430 for (imm = 0; *str && ISDIGIT (*str); ++str)
404ff6b5
AH
9431 imm = imm * 10 + *str - '0';
9432
9433 if (imm > 64)
9434 {
9435 inst.error = _("immediate out of range");
9436 return;
9437 }
9438
9439 /* Make negative imm's into 7bit signed numbers. */
9440 if (neg)
9441 {
9442 imm = -imm;
9443 imm &= 0x0000007f;
9444 }
9445
9446 /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
9447 Bits 5-7 of the insn should have bits 4-6 of the immediate.
9448 Bit 4 should be 0. */
9449 imm = (imm & 0xf) | ((imm & 0x70) << 1);
9450
9451 inst.instruction |= imm;
404ff6b5 9452 end_of_line (str);
404ff6b5
AH
9453}
9454
9455static int
63e63b07 9456mav_parse_offset (str, negative)
404ff6b5
AH
9457 char ** str;
9458 int *negative;
9459{
9460 char * p = *str;
9461 int offset;
9462
9463 *negative = 0;
9464
9465 skip_whitespace (p);
9466
9467 if (*p == '#')
9468 ++p;
9469
9470 if (*p == '-')
9471 {
9472 *negative = 1;
9473 ++p;
9474 }
9475
8420dfca 9476 if (!ISDIGIT (*p))
404ff6b5
AH
9477 {
9478 inst.error = _("offset expected");
9479 return 0;
9480 }
9481
8420dfca 9482 for (offset = 0; *p && ISDIGIT (*p); ++p)
404ff6b5
AH
9483 offset = offset * 10 + *p - '0';
9484
9485 if (offset > 0xff)
9486 {
9487 inst.error = _("offset out of range");
9488 return 0;
9489 }
9490
9491 *str = p;
9492
9493 return *negative ? -offset : offset;
9494}
9495
63e63b07 9496/* Maverick load/store instructions.
404ff6b5
AH
9497 <insn><cond> CRd,[Rn,<offset>]{!}.
9498 <insn><cond> CRd,[Rn],<offset>. */
9499
9500static void
63e63b07 9501do_mav_ldst (str, reg0)
404ff6b5 9502 char * str;
6c43fab6 9503 enum arm_reg_type reg0;
404ff6b5
AH
9504{
9505 int offset, negative;
404ff6b5
AH
9506
9507 skip_whitespace (str);
9508
63e63b07 9509 if (mav_reg_required_here (&str, 12, reg0) == FAIL
6c43fab6 9510 || skip_past_comma (&str) == FAIL
404ff6b5 9511 || *str++ != '['
6c43fab6 9512 || reg_required_here (&str, 16) == FAIL)
404ff6b5
AH
9513 goto fail_ldst;
9514
6c43fab6 9515 if (skip_past_comma (&str) == SUCCESS)
404ff6b5
AH
9516 {
9517 /* You are here: "<offset>]{!}". */
9518 inst.instruction |= PRE_INDEX;
9519
63e63b07 9520 offset = mav_parse_offset (&str, &negative);
404ff6b5
AH
9521
9522 if (inst.error)
9523 return;
9524
9525 if (*str++ != ']')
9526 {
9527 inst.error = _("missing ]");
9528 return;
9529 }
9530
9531 if (*str == '!')
9532 {
9533 inst.instruction |= WRITE_BACK;
9534 ++str;
9535 }
9536 }
9537 else
9538 {
9539 /* You are here: "], <offset>". */
9540 if (*str++ != ']')
9541 {
9542 inst.error = _("missing ]");
9543 return;
9544 }
9545
9546 if (skip_past_comma (&str) == FAIL
63e63b07 9547 || (offset = mav_parse_offset (&str, &negative), inst.error))
404ff6b5
AH
9548 goto fail_ldst;
9549
9550 inst.instruction |= CP_T_WB; /* Post indexed, set bit W. */
9551 }
9552
9553 if (negative)
9554 offset = -offset;
9555 else
9556 inst.instruction |= CP_T_UD; /* Postive, so set bit U. */
9557
9558 inst.instruction |= offset >> 2;
404ff6b5
AH
9559 end_of_line (str);
9560 return;
9561
9562fail_ldst:
9563 if (!inst.error)
9564 inst.error = BAD_ARGS;
9565 return;
9566}
9567
b99bd4ef
NC
9568static void
9569do_t_nop (str)
9570 char * str;
9571{
9572 /* Do nothing. */
9573 end_of_line (str);
9574 return;
9575}
9576
9577/* Handle the Format 4 instructions that do not have equivalents in other
9578 formats. That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
9579 BIC and MVN. */
9580
9581static void
9582do_t_arit (str)
9583 char * str;
9584{
9585 int Rd, Rs, Rn;
9586
9587 skip_whitespace (str);
9588
9589 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9590 || skip_past_comma (&str) == FAIL
9591 || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9592 {
9593 inst.error = BAD_ARGS;
9594 return;
9595 }
9596
9597 if (skip_past_comma (&str) != FAIL)
9598 {
9599 /* Three operand format not allowed for TST, CMN, NEG and MVN.
9600 (It isn't allowed for CMP either, but that isn't handled by this
9601 function.) */
9602 if (inst.instruction == T_OPCODE_TST
9603 || inst.instruction == T_OPCODE_CMN
9604 || inst.instruction == T_OPCODE_NEG
9605 || inst.instruction == T_OPCODE_MVN)
9606 {
9607 inst.error = BAD_ARGS;
9608 return;
9609 }
9610
9611 if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9612 return;
9613
9614 if (Rs != Rd)
9615 {
9616 inst.error = _("dest and source1 must be the same register");
9617 return;
9618 }
9619 Rs = Rn;
9620 }
9621
9622 if (inst.instruction == T_OPCODE_MUL
9623 && Rs == Rd)
9624 as_tsktsk (_("Rs and Rd must be different in MUL"));
9625
9626 inst.instruction |= Rd | (Rs << 3);
9627 end_of_line (str);
9628}
9629
9630static void
9631do_t_add (str)
9632 char * str;
9633{
9634 thumb_add_sub (str, 0);
9635}
9636
9637static void
9638do_t_asr (str)
9639 char * str;
9640{
9641 thumb_shift (str, THUMB_ASR);
9642}
9643
9644static void
9645do_t_branch9 (str)
9646 char * str;
9647{
9648 if (my_get_expression (&inst.reloc.exp, &str))
9649 return;
9650 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
9651 inst.reloc.pc_rel = 1;
9652 end_of_line (str);
9653}
9654
9655static void
9656do_t_branch12 (str)
9657 char * str;
9658{
9659 if (my_get_expression (&inst.reloc.exp, &str))
9660 return;
9661 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
9662 inst.reloc.pc_rel = 1;
9663 end_of_line (str);
9664}
9665
9666/* Find the real, Thumb encoded start of a Thumb function. */
9667
9668static symbolS *
9669find_real_start (symbolP)
9670 symbolS * symbolP;
9671{
9672 char * real_start;
9673 const char * name = S_GET_NAME (symbolP);
9674 symbolS * new_target;
9675
9676 /* This definiton must agree with the one in gcc/config/arm/thumb.c. */
9677#define STUB_NAME ".real_start_of"
9678
9679 if (name == NULL)
9680 abort ();
9681
9682 /* Names that start with '.' are local labels, not function entry points.
9683 The compiler may generate BL instructions to these labels because it
9684 needs to perform a branch to a far away location. */
9685 if (name[0] == '.')
9686 return symbolP;
9687
9688 real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1);
9689 sprintf (real_start, "%s%s", STUB_NAME, name);
9690
9691 new_target = symbol_find (real_start);
9692
9693 if (new_target == NULL)
9694 {
9695 as_warn ("Failed to find real start of function: %s\n", name);
9696 new_target = symbolP;
9697 }
9698
9699 free (real_start);
9700
9701 return new_target;
9702}
9703
9704static void
9705do_t_branch23 (str)
9706 char * str;
9707{
9708 if (my_get_expression (& inst.reloc.exp, & str))
9709 return;
9710
9711 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
9712 inst.reloc.pc_rel = 1;
9713 end_of_line (str);
9714
9715 /* If the destination of the branch is a defined symbol which does not have
9716 the THUMB_FUNC attribute, then we must be calling a function which has
9717 the (interfacearm) attribute. We look for the Thumb entry point to that
9718 function and change the branch to refer to that function instead. */
9719 if ( inst.reloc.exp.X_op == O_symbol
9720 && inst.reloc.exp.X_add_symbol != NULL
9721 && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
9722 && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
9723 inst.reloc.exp.X_add_symbol =
9724 find_real_start (inst.reloc.exp.X_add_symbol);
9725}
9726
9727static void
9728do_t_bx (str)
9729 char * str;
9730{
9731 int reg;
9732
9733 skip_whitespace (str);
9734
9735 if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
9736 return;
9737
9738 /* This sets THUMB_H2 from the top bit of reg. */
9739 inst.instruction |= reg << 3;
9740
9741 /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc
9742 should cause the alignment to be checked once it is known. This is
9743 because BX PC only works if the instruction is word aligned. */
9744
9745 end_of_line (str);
9746}
9747
9748static void
9749do_t_compare (str)
9750 char * str;
9751{
9752 thumb_mov_compare (str, THUMB_COMPARE);
9753}
9754
9755static void
9756do_t_ldmstm (str)
9757 char * str;
9758{
9759 int Rb;
9760 long range;
9761
9762 skip_whitespace (str);
9763
9764 if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9765 return;
9766
9767 if (*str != '!')
f03698e6 9768 as_warn (_("inserted missing '!': load/store multiple always writes back base register"));
b99bd4ef
NC
9769 else
9770 str++;
9771
9772 if (skip_past_comma (&str) == FAIL
9773 || (range = reg_list (&str)) == FAIL)
9774 {
9775 if (! inst.error)
9776 inst.error = BAD_ARGS;
9777 return;
9778 }
9779
9780 if (inst.reloc.type != BFD_RELOC_NONE)
9781 {
9782 /* This really doesn't seem worth it. */
9783 inst.reloc.type = BFD_RELOC_NONE;
f03698e6 9784 inst.error = _("expression too complex");
b99bd4ef
NC
9785 return;
9786 }
9787
9788 if (range & ~0xff)
9789 {
9790 inst.error = _("only lo-regs valid in load/store multiple");
9791 return;
9792 }
9793
9794 inst.instruction |= (Rb << 8) | range;
9795 end_of_line (str);
9796}
9797
9798static void
9799do_t_ldr (str)
9800 char * str;
9801{
9802 thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
9803}
9804
9805static void
9806do_t_ldrb (str)
9807 char * str;
9808{
9809 thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
9810}
9811
9812static void
9813do_t_ldrh (str)
9814 char * str;
9815{
9816 thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
9817}
9818
9819static void
9820do_t_lds (str)
9821 char * str;
9822{
9823 int Rd, Rb, Ro;
9824
9825 skip_whitespace (str);
9826
9827 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9828 || skip_past_comma (&str) == FAIL
9829 || *str++ != '['
9830 || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9831 || skip_past_comma (&str) == FAIL
9832 || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9833 || *str++ != ']')
9834 {
9835 if (! inst.error)
f03698e6 9836 inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]");
b99bd4ef
NC
9837 return;
9838 }
9839
9840 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
9841 end_of_line (str);
9842}
9843
9844static void
9845do_t_lsl (str)
9846 char * str;
9847{
9848 thumb_shift (str, THUMB_LSL);
9849}
9850
9851static void
9852do_t_lsr (str)
9853 char * str;
9854{
9855 thumb_shift (str, THUMB_LSR);
9856}
9857
9858static void
9859do_t_mov (str)
9860 char * str;
9861{
9862 thumb_mov_compare (str, THUMB_MOVE);
9863}
9864
9865static void
9866do_t_push_pop (str)
9867 char * str;
9868{
9869 long range;
9870
9871 skip_whitespace (str);
9872
9873 if ((range = reg_list (&str)) == FAIL)
9874 {
9875 if (! inst.error)
9876 inst.error = BAD_ARGS;
9877 return;
9878 }
9879
9880 if (inst.reloc.type != BFD_RELOC_NONE)
9881 {
9882 /* This really doesn't seem worth it. */
9883 inst.reloc.type = BFD_RELOC_NONE;
f03698e6 9884 inst.error = _("expression too complex");
b99bd4ef
NC
9885 return;
9886 }
9887
9888 if (range & ~0xff)
9889 {
9890 if ((inst.instruction == T_OPCODE_PUSH
9891 && (range & ~0xff) == 1 << REG_LR)
9892 || (inst.instruction == T_OPCODE_POP
9893 && (range & ~0xff) == 1 << REG_PC))
9894 {
9895 inst.instruction |= THUMB_PP_PC_LR;
9896 range &= 0xff;
9897 }
9898 else
9899 {
9900 inst.error = _("invalid register list to push/pop instruction");
9901 return;
9902 }
9903 }
9904
9905 inst.instruction |= range;
9906 end_of_line (str);
9907}
9908
9909static void
9910do_t_str (str)
9911 char * str;
9912{
9913 thumb_load_store (str, THUMB_STORE, THUMB_WORD);
9914}
9915
9916static void
9917do_t_strb (str)
9918 char * str;
9919{
9920 thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
9921}
9922
9923static void
9924do_t_strh (str)
9925 char * str;
9926{
9927 thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
9928}
9929
9930static void
9931do_t_sub (str)
9932 char * str;
9933{
9934 thumb_add_sub (str, 1);
9935}
9936
9937static void
9938do_t_swi (str)
9939 char * str;
9940{
9941 skip_whitespace (str);
9942
9943 if (my_get_expression (&inst.reloc.exp, &str))
9944 return;
9945
9946 inst.reloc.type = BFD_RELOC_ARM_SWI;
9947 end_of_line (str);
9948 return;
9949}
9950
9951static void
9952do_t_adr (str)
9953 char * str;
9954{
9955 int reg;
9956
9957 /* This is a pseudo-op of the form "adr rd, label" to be converted
9958 into a relative address of the form "add rd, pc, #label-.-4". */
9959 skip_whitespace (str);
9960
9961 /* Store Rd in temporary location inside instruction. */
9962 if ((reg = reg_required_here (&str, 4)) == FAIL
9963 || (reg > 7) /* For Thumb reg must be r0..r7. */
9964 || skip_past_comma (&str) == FAIL
9965 || my_get_expression (&inst.reloc.exp, &str))
9966 {
9967 if (!inst.error)
9968 inst.error = BAD_ARGS;
9969 return;
9970 }
9971
9972 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
9973 inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */
9974 inst.reloc.pc_rel = 1;
9975 inst.instruction |= REG_PC; /* Rd is already placed into the instruction. */
9976
9977 end_of_line (str);
9978}
9979
9980static void
6c43fab6
RE
9981insert_reg (r, htab)
9982 const struct reg_entry *r;
9983 struct hash_control *htab;
b99bd4ef 9984{
6c43fab6 9985 int len = strlen (r->name) + 2;
b99bd4ef
NC
9986 char * buf = (char *) xmalloc (len);
9987 char * buf2 = (char *) xmalloc (len);
9988 int i = 0;
9989
9990#ifdef REGISTER_PREFIX
9991 buf[i++] = REGISTER_PREFIX;
9992#endif
9993
6c43fab6 9994 strcpy (buf + i, r->name);
b99bd4ef
NC
9995
9996 for (i = 0; buf[i]; i++)
3882b010 9997 buf2[i] = TOUPPER (buf[i]);
b99bd4ef
NC
9998
9999 buf2[i] = '\0';
10000
6c43fab6
RE
10001 hash_insert (htab, buf, (PTR) r);
10002 hash_insert (htab, buf2, (PTR) r);
b99bd4ef
NC
10003}
10004
10005static void
6c43fab6
RE
10006build_reg_hsh (map)
10007 struct reg_map *map;
10008{
10009 const struct reg_entry *r;
10010
10011 if ((map->htab = hash_new ()) == NULL)
f03698e6 10012 as_fatal (_("virtual memory exhausted"));
6c43fab6
RE
10013
10014 for (r = map->names; r->name != NULL; r++)
10015 insert_reg (r, map->htab);
10016}
10017
10018static void
10019insert_reg_alias (str, regnum, htab)
b99bd4ef
NC
10020 char *str;
10021 int regnum;
6c43fab6 10022 struct hash_control *htab;
b99bd4ef
NC
10023{
10024 struct reg_entry *new =
10025 (struct reg_entry *) xmalloc (sizeof (struct reg_entry));
10026 char *name = xmalloc (strlen (str) + 1);
10027 strcpy (name, str);
10028
10029 new->name = name;
10030 new->number = regnum;
10031
6c43fab6 10032 hash_insert (htab, name, (PTR) new);
b99bd4ef
NC
10033}
10034
6c43fab6
RE
10035/* Look for the .req directive. This is of the form:
10036
10037 newname .req existing_name
10038
10039 If we find one, or if it looks sufficiently like one that we want to
10040 handle any error here, return non-zero. Otherwise return zero. */
10041static int
10042create_register_alias (newname, p)
10043 char *newname;
10044 char *p;
10045{
10046 char *q;
10047 char c;
10048
10049 q = p;
10050 skip_whitespace (q);
10051
10052 c = *p;
10053 *p = '\0';
10054
10055 if (*q && !strncmp (q, ".req ", 5))
10056 {
10057 char *copy_of_str;
10058 char *r;
10059
10060#ifdef IGNORE_OPCODE_CASE
10061 newname = original_case_string;
10062#endif
10063 copy_of_str = newname;
10064
10065 q += 4;
10066 skip_whitespace (q);
10067
10068 for (r = q; *r != '\0'; r++)
10069 if (*r == ' ')
10070 break;
10071
10072 if (r != q)
10073 {
10074 enum arm_reg_type new_type, old_type;
10075 int old_regno;
10076 char d = *r;
10077
10078 *r = '\0';
10079 old_type = arm_reg_parse_any (q);
10080 *r = d;
10081
10082 new_type = arm_reg_parse_any (newname);
10083
10084 if (new_type == REG_TYPE_MAX)
10085 {
10086 if (old_type != REG_TYPE_MAX)
10087 {
10088 old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab);
10089 insert_reg_alias (newname, old_regno,
10090 all_reg_maps[old_type].htab);
10091 }
10092 else
10093 as_warn (_("register '%s' does not exist\n"), q);
10094 }
10095 else if (old_type == REG_TYPE_MAX)
10096 {
10097 as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
10098 copy_of_str, q);
10099 }
10100 else
10101 {
10102 /* Do not warn about redefinitions to the same alias. */
10103 if (new_type != old_type
10104 || (arm_reg_parse (&q, all_reg_maps[old_type].htab)
10105 != arm_reg_parse (&q, all_reg_maps[new_type].htab)))
10106 as_warn (_("ignoring redefinition of register alias '%s'"),
10107 copy_of_str);
10108
10109 }
10110 }
10111 else
10112 as_warn (_("ignoring incomplete .req pseuso op"));
10113
10114 *p = c;
10115 return 1;
10116 }
10117 *p = c;
10118 return 0;
10119}
cc8a6dd0 10120
b99bd4ef
NC
10121static void
10122set_constant_flonums ()
10123{
10124 int i;
10125
10126 for (i = 0; i < NUM_FLOAT_VALS; i++)
10127 if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
10128 abort ();
10129}
10130
90e4755a
RE
10131/* Iterate over the base tables to create the instruction patterns. */
10132static void
10133build_arm_ops_hsh ()
10134{
10135 unsigned int i;
10136 unsigned int j;
10137 static struct obstack insn_obstack;
10138
10139 obstack_begin (&insn_obstack, 4000);
10140
10141 for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
10142 {
6c43fab6 10143 const struct asm_opcode *insn = insns + i;
90e4755a
RE
10144
10145 if (insn->cond_offset != 0)
10146 {
10147 /* Insn supports conditional execution. Build the varaints
10148 and insert them in the hash table. */
10149 for (j = 0; j < sizeof (conds) / sizeof (struct asm_cond); j++)
10150 {
10151 unsigned len = strlen (insn->template);
10152 struct asm_opcode *new;
10153 char *template;
10154
10155 new = obstack_alloc (&insn_obstack, sizeof (struct asm_opcode));
10156 /* All condition codes are two characters. */
10157 template = obstack_alloc (&insn_obstack, len + 3);
10158
10159 strncpy (template, insn->template, insn->cond_offset);
10160 strcpy (template + insn->cond_offset, conds[j].template);
10161 if (len > insn->cond_offset)
10162 strcpy (template + insn->cond_offset + 2,
10163 insn->template + insn->cond_offset);
10164 new->template = template;
10165 new->cond_offset = 0;
10166 new->variant = insn->variant;
10167 new->parms = insn->parms;
10168 new->value = (insn->value & ~COND_MASK) | conds[j].value;
10169
10170 hash_insert (arm_ops_hsh, new->template, (PTR) new);
10171 }
10172 }
10173 /* Finally, insert the unconditional insn in the table directly;
10174 no need to build a copy. */
10175 hash_insert (arm_ops_hsh, insn->template, (PTR) insn);
10176 }
10177}
10178
5a6c6817
NC
10179#if defined OBJ_ELF || defined OBJ_COFF
10180
10181#ifdef OBJ_ELF
10182#define arm_Note Elf_External_Note
10183#else
10184typedef struct
10185{
10186 unsigned char namesz[4]; /* Size of entry's owner string. */
10187 unsigned char descsz[4]; /* Size of the note descriptor. */
10188 unsigned char type[4]; /* Interpretation of the descriptor. */
10189 char name[1]; /* Start of the name+desc data. */
10190} arm_Note;
10191#endif
10192
10193/* The description is kept to a fix sized in order to make updating
10194 it and merging it easier. */
10195#define ARM_NOTE_DESCRIPTION_LENGTH 8
10196
10197static void
10198arm_add_note (name, description, type)
10199 const char * name;
10200 const char * description;
10201 unsigned int type;
10202{
10203 arm_Note note ATTRIBUTE_UNUSED;
10204 char * p;
10205 unsigned int name_len;
10206
10207 name_len = (strlen (name) + 1 + 3) & ~3;
10208
10209 p = frag_more (sizeof (note.namesz));
10210 md_number_to_chars (p, (valueT) name_len, sizeof (note.namesz));
10211
10212 p = frag_more (sizeof (note.descsz));
10213 md_number_to_chars (p, (valueT) ARM_NOTE_DESCRIPTION_LENGTH, sizeof (note.descsz));
10214
10215 p = frag_more (sizeof (note.type));
10216 md_number_to_chars (p, (valueT) type, sizeof (note.type));
10217
10218 p = frag_more (name_len);
10219 strcpy (p, name);
10220
10221 p = frag_more (ARM_NOTE_DESCRIPTION_LENGTH);
10222 strncpy (p, description, ARM_NOTE_DESCRIPTION_LENGTH);
10223 frag_align (2, 0, 0);
10224}
10225#endif
10226
b99bd4ef
NC
10227void
10228md_begin ()
10229{
10230 unsigned mach;
10231 unsigned int i;
10232
10233 if ( (arm_ops_hsh = hash_new ()) == NULL
10234 || (arm_tops_hsh = hash_new ()) == NULL
10235 || (arm_cond_hsh = hash_new ()) == NULL
10236 || (arm_shift_hsh = hash_new ()) == NULL
b99bd4ef 10237 || (arm_psr_hsh = hash_new ()) == NULL)
f03698e6 10238 as_fatal (_("virtual memory exhausted"));
b99bd4ef 10239
90e4755a 10240 build_arm_ops_hsh ();
b99bd4ef
NC
10241 for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++)
10242 hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i));
10243 for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
10244 hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
10245 for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
10246 hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
10247 for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
10248 hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
10249
6c43fab6
RE
10250 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
10251 build_reg_hsh (all_reg_maps + i);
b99bd4ef
NC
10252
10253 set_constant_flonums ();
10254
03b1477f
RE
10255 /* Set the cpu variant based on the command-line options. We prefer
10256 -mcpu= over -march= if both are set (as for GCC); and we prefer
10257 -mfpu= over any other way of setting the floating point unit.
10258 Use of legacy options with new options are faulted. */
10259 if (legacy_cpu != -1)
10260 {
10261 if (mcpu_cpu_opt != -1 || march_cpu_opt != -1)
10262 as_bad (_("use of old and new-style options to set CPU type"));
10263
10264 mcpu_cpu_opt = legacy_cpu;
10265 }
10266 else if (mcpu_cpu_opt == -1)
10267 mcpu_cpu_opt = march_cpu_opt;
10268
10269 if (legacy_fpu != -1)
10270 {
10271 if (mfpu_opt != -1)
10272 as_bad (_("use of old and new-style options to set FPU type"));
10273
10274 mfpu_opt = legacy_fpu;
10275 }
10276 else if (mfpu_opt == -1)
10277 {
39c2da32
RE
10278#if !(defined (TE_LINUX) || defined (TE_NetBSD))
10279 /* Some environments specify a default FPU. If they don't, infer it
10280 from the processor. */
03b1477f
RE
10281 if (mcpu_fpu_opt != -1)
10282 mfpu_opt = mcpu_fpu_opt;
10283 else
10284 mfpu_opt = march_fpu_opt;
39c2da32
RE
10285#else
10286 mfpu_opt = FPU_DEFAULT;
10287#endif
03b1477f
RE
10288 }
10289
10290 if (mfpu_opt == -1)
10291 {
10292 if (mcpu_cpu_opt == -1)
10293 mfpu_opt = FPU_DEFAULT;
10294 else if (mcpu_cpu_opt & ARM_EXT_V5)
10295 mfpu_opt = FPU_ARCH_VFP_V2;
10296 else
10297 mfpu_opt = FPU_ARCH_FPA;
10298 }
10299
10300 if (mcpu_cpu_opt == -1)
10301 mcpu_cpu_opt = CPU_DEFAULT;
10302
10303 cpu_variant = mcpu_cpu_opt | mfpu_opt;
10304
b99bd4ef
NC
10305#if defined OBJ_COFF || defined OBJ_ELF
10306 {
10307 unsigned int flags = 0;
10308
10309 /* Set the flags in the private structure. */
10310 if (uses_apcs_26) flags |= F_APCS26;
10311 if (support_interwork) flags |= F_INTERWORK;
10312 if (uses_apcs_float) flags |= F_APCS_FLOAT;
10313 if (pic_code) flags |= F_PIC;
bfae80f2 10314 if ((cpu_variant & FPU_ANY) == FPU_NONE
03b1477f 10315 || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only. */
bfae80f2 10316 flags |= F_SOFT_FLOAT;
03b1477f
RE
10317 /* Using VFP conventions (even if soft-float). */
10318 if (cpu_variant & FPU_VFP_EXT_NONE) flags |= F_VFP_FLOAT;
10319
fde78edd
NC
10320#if defined OBJ_ELF
10321 if (cpu_variant & ARM_CEXT_MAVERICK)
10322 {
10323 flags ^= F_SOFT_FLOAT;
10324 flags |= EF_ARM_MAVERICK_FLOAT;
10325 }
10326#endif
b99bd4ef
NC
10327
10328 bfd_set_private_flags (stdoutput, flags);
10329
10330 /* We have run out flags in the COFF header to encode the
10331 status of ATPCS support, so instead we create a dummy,
10332 empty, debug section called .arm.atpcs. */
10333 if (atpcs)
10334 {
10335 asection * sec;
10336
10337 sec = bfd_make_section (stdoutput, ".arm.atpcs");
10338
10339 if (sec != NULL)
10340 {
10341 bfd_set_section_flags
10342 (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
10343 bfd_set_section_size (stdoutput, sec, 0);
10344 bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
10345 }
10346 }
10347 }
10348#endif
10349
10350 /* Record the CPU type as well. */
10351 switch (cpu_variant & ARM_CPU_MASK)
10352 {
10353 case ARM_2:
10354 mach = bfd_mach_arm_2;
10355 break;
10356
10357 case ARM_3: /* Also ARM_250. */
10358 mach = bfd_mach_arm_2a;
10359 break;
10360
b89dddec
RE
10361 case ARM_6: /* Also ARM_7. */
10362 mach = bfd_mach_arm_3;
10363 break;
10364
b99bd4ef 10365 default:
5a6c6817 10366 mach = bfd_mach_arm_unknown;
b99bd4ef 10367 break;
b99bd4ef
NC
10368 }
10369
10370 /* Catch special cases. */
e16bb312
NC
10371 if (cpu_variant & ARM_CEXT_IWMMXT)
10372 mach = bfd_mach_arm_iWMMXt;
10373 else if (cpu_variant & ARM_CEXT_XSCALE)
b99bd4ef 10374 mach = bfd_mach_arm_XScale;
fde78edd
NC
10375 else if (cpu_variant & ARM_CEXT_MAVERICK)
10376 mach = bfd_mach_arm_ep9312;
b99bd4ef
NC
10377 else if (cpu_variant & ARM_EXT_V5E)
10378 mach = bfd_mach_arm_5TE;
10379 else if (cpu_variant & ARM_EXT_V5)
10380 {
b89dddec 10381 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
10382 mach = bfd_mach_arm_5T;
10383 else
10384 mach = bfd_mach_arm_5;
10385 }
b89dddec 10386 else if (cpu_variant & ARM_EXT_V4)
b99bd4ef 10387 {
b89dddec 10388 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
10389 mach = bfd_mach_arm_4T;
10390 else
10391 mach = bfd_mach_arm_4;
10392 }
b89dddec 10393 else if (cpu_variant & ARM_EXT_V3M)
b99bd4ef
NC
10394 mach = bfd_mach_arm_3M;
10395
5a6c6817 10396#if 0 /* Suppressed - for now. */
e16bb312 10397#if defined (OBJ_ELF) || defined (OBJ_COFF)
5a6c6817
NC
10398
10399 /* Create a .note section to fully identify this arm binary. */
10400
10401#define NOTE_ARCH_STRING "arch: "
10402
10403#if defined OBJ_COFF && ! defined NT_VERSION
10404#define NT_VERSION 1
10405#define NT_ARCH 2
10406#endif
10407
e16bb312 10408 {
e16bb312
NC
10409 segT current_seg = now_seg;
10410 subsegT current_subseg = now_subseg;
10411 asection * arm_arch;
5a6c6817
NC
10412 const char * arch_string;
10413
e16bb312
NC
10414 arm_arch = bfd_make_section_old_way (stdoutput, ARM_NOTE_SECTION);
10415
10416#ifdef OBJ_COFF
10417 bfd_set_section_flags (stdoutput, arm_arch,
10418 SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_LINK_ONCE \
10419 | SEC_HAS_CONTENTS);
10420#endif
10421 arm_arch->output_section = arm_arch;
10422 subseg_set (arm_arch, 0);
e16bb312 10423
5a6c6817
NC
10424 switch (mach)
10425 {
10426 default:
10427 case bfd_mach_arm_unknown: arch_string = "unknown"; break;
10428 case bfd_mach_arm_2: arch_string = "armv2"; break;
10429 case bfd_mach_arm_2a: arch_string = "armv2a"; break;
10430 case bfd_mach_arm_3: arch_string = "armv3"; break;
10431 case bfd_mach_arm_3M: arch_string = "armv3M"; break;
10432 case bfd_mach_arm_4: arch_string = "armv4"; break;
10433 case bfd_mach_arm_4T: arch_string = "armv4t"; break;
10434 case bfd_mach_arm_5: arch_string = "armv5"; break;
10435 case bfd_mach_arm_5T: arch_string = "armv5t"; break;
10436 case bfd_mach_arm_5TE: arch_string = "armv5te"; break;
10437 case bfd_mach_arm_XScale: arch_string = "XScale"; break;
10438 case bfd_mach_arm_ep9312: arch_string = "ep9312"; break;
10439 case bfd_mach_arm_iWMMXt: arch_string = "iWMMXt"; break;
10440 }
10441
10442 arm_add_note (NOTE_ARCH_STRING, arch_string, NT_ARCH);
e16bb312
NC
10443
10444 subseg_set (current_seg, current_subseg);
10445 }
10446#endif
5a6c6817
NC
10447#endif /* Suppressed code. */
10448
b99bd4ef
NC
10449 bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
10450}
10451
10452/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
10453 for use in the a.out file, and stores them in the array pointed to by buf.
10454 This knows about the endian-ness of the target machine and does
10455 THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
10456 2 (short) and 4 (long) Floating numbers are put out as a series of
10457 LITTLENUMS (shorts, here at least). */
10458
10459void
10460md_number_to_chars (buf, val, n)
10461 char * buf;
10462 valueT val;
10463 int n;
10464{
10465 if (target_big_endian)
10466 number_to_chars_bigendian (buf, val, n);
10467 else
10468 number_to_chars_littleendian (buf, val, n);
10469}
10470
10471static valueT
10472md_chars_to_number (buf, n)
10473 char * buf;
10474 int n;
10475{
10476 valueT result = 0;
10477 unsigned char * where = (unsigned char *) buf;
10478
10479 if (target_big_endian)
10480 {
10481 while (n--)
10482 {
10483 result <<= 8;
10484 result |= (*where++ & 255);
10485 }
10486 }
10487 else
10488 {
10489 while (n--)
10490 {
10491 result <<= 8;
10492 result |= (where[n] & 255);
10493 }
10494 }
10495
10496 return result;
10497}
10498
10499/* Turn a string in input_line_pointer into a floating point constant
10500 of type TYPE, and store the appropriate bytes in *LITP. The number
10501 of LITTLENUMS emitted is stored in *SIZEP. An error message is
10502 returned, or NULL on OK.
10503
10504 Note that fp constants aren't represent in the normal way on the ARM.
10505 In big endian mode, things are as expected. However, in little endian
10506 mode fp constants are big-endian word-wise, and little-endian byte-wise
10507 within the words. For example, (double) 1.1 in big endian mode is
10508 the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
10509 the byte sequence 99 99 f1 3f 9a 99 99 99.
10510
10511 ??? The format of 12 byte floats is uncertain according to gcc's arm.h. */
10512
10513char *
10514md_atof (type, litP, sizeP)
10515 char type;
10516 char * litP;
10517 int * sizeP;
10518{
10519 int prec;
10520 LITTLENUM_TYPE words[MAX_LITTLENUMS];
10521 char *t;
10522 int i;
10523
10524 switch (type)
10525 {
10526 case 'f':
10527 case 'F':
10528 case 's':
10529 case 'S':
10530 prec = 2;
10531 break;
10532
10533 case 'd':
10534 case 'D':
10535 case 'r':
10536 case 'R':
10537 prec = 4;
10538 break;
10539
10540 case 'x':
10541 case 'X':
10542 prec = 6;
10543 break;
10544
10545 case 'p':
10546 case 'P':
10547 prec = 6;
10548 break;
10549
10550 default:
10551 *sizeP = 0;
f03698e6 10552 return _("bad call to MD_ATOF()");
b99bd4ef
NC
10553 }
10554
10555 t = atof_ieee (input_line_pointer, type, words);
10556 if (t)
10557 input_line_pointer = t;
10558 *sizeP = prec * 2;
10559
10560 if (target_big_endian)
10561 {
10562 for (i = 0; i < prec; i++)
10563 {
10564 md_number_to_chars (litP, (valueT) words[i], 2);
10565 litP += 2;
10566 }
10567 }
10568 else
10569 {
bfae80f2
RE
10570 if (cpu_variant & FPU_ARCH_VFP)
10571 for (i = prec - 1; i >= 0; i--)
10572 {
10573 md_number_to_chars (litP, (valueT) words[i], 2);
10574 litP += 2;
10575 }
10576 else
10577 /* For a 4 byte float the order of elements in `words' is 1 0.
10578 For an 8 byte float the order is 1 0 3 2. */
10579 for (i = 0; i < prec; i += 2)
10580 {
10581 md_number_to_chars (litP, (valueT) words[i + 1], 2);
10582 md_number_to_chars (litP + 2, (valueT) words[i], 2);
10583 litP += 4;
10584 }
b99bd4ef
NC
10585 }
10586
10587 return 0;
10588}
10589
10590/* The knowledge of the PC's pipeline offset is built into the insns
10591 themselves. */
10592
10593long
10594md_pcrel_from (fixP)
10595 fixS * fixP;
10596{
10597 if (fixP->fx_addsy
10598 && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
10599 && fixP->fx_subsy == NULL)
10600 return 0;
10601
10602 if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD))
10603 {
10604 /* PC relative addressing on the Thumb is slightly odd
10605 as the bottom two bits of the PC are forced to zero
10606 for the calculation. */
10607 return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
10608 }
10609
10610#ifdef TE_WINCE
10611 /* The pattern was adjusted to accomodate CE's off-by-one fixups,
10612 so we un-adjust here to compensate for the accomodation. */
10613 return fixP->fx_where + fixP->fx_frag->fr_address + 8;
10614#else
10615 return fixP->fx_where + fixP->fx_frag->fr_address;
10616#endif
10617}
10618
10619/* Round up a section size to the appropriate boundary. */
10620
10621valueT
10622md_section_align (segment, size)
10623 segT segment ATTRIBUTE_UNUSED;
10624 valueT size;
10625{
10626#ifdef OBJ_ELF
10627 return size;
10628#else
10629 /* Round all sects to multiple of 4. */
10630 return (size + 3) & ~3;
10631#endif
10632}
10633
10634/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
10635 Otherwise we have no need to default values of symbols. */
10636
10637symbolS *
10638md_undefined_symbol (name)
10639 char * name ATTRIBUTE_UNUSED;
10640{
10641#ifdef OBJ_ELF
10642 if (name[0] == '_' && name[1] == 'G'
10643 && streq (name, GLOBAL_OFFSET_TABLE_NAME))
10644 {
10645 if (!GOT_symbol)
10646 {
10647 if (symbol_find (name))
10648 as_bad ("GOT already in the symbol table");
10649
10650 GOT_symbol = symbol_new (name, undefined_section,
10651 (valueT) 0, & zero_address_frag);
10652 }
10653
10654 return GOT_symbol;
10655 }
10656#endif
10657
10658 return 0;
10659}
10660
10661/* arm_reg_parse () := if it looks like a register, return its token and
10662 advance the pointer. */
10663
10664static int
6c43fab6 10665arm_reg_parse (ccp, htab)
b99bd4ef 10666 register char ** ccp;
6c43fab6 10667 struct hash_control *htab;
b99bd4ef
NC
10668{
10669 char * start = * ccp;
10670 char c;
10671 char * p;
10672 struct reg_entry * reg;
10673
10674#ifdef REGISTER_PREFIX
10675 if (*start != REGISTER_PREFIX)
10676 return FAIL;
10677 p = start + 1;
10678#else
10679 p = start;
10680#ifdef OPTIONAL_REGISTER_PREFIX
10681 if (*p == OPTIONAL_REGISTER_PREFIX)
10682 p++, start++;
10683#endif
10684#endif
3882b010 10685 if (!ISALPHA (*p) || !is_name_beginner (*p))
b99bd4ef
NC
10686 return FAIL;
10687
10688 c = *p++;
3882b010 10689 while (ISALPHA (c) || ISDIGIT (c) || c == '_')
b99bd4ef
NC
10690 c = *p++;
10691
10692 *--p = 0;
6c43fab6 10693 reg = (struct reg_entry *) hash_find (htab, start);
b99bd4ef
NC
10694 *p = c;
10695
10696 if (reg)
10697 {
10698 *ccp = p;
10699 return reg->number;
10700 }
10701
10702 return FAIL;
10703}
10704
6c43fab6
RE
10705/* Search for the following register name in each of the possible reg name
10706 tables. Return the classification if found, or REG_TYPE_MAX if not
10707 present. */
10708static enum arm_reg_type
10709arm_reg_parse_any (cp)
10710 char *cp;
10711{
10712 int i;
10713
10714 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
10715 if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL)
10716 return (enum arm_reg_type) i;
10717
10718 return REG_TYPE_MAX;
10719}
10720
94f592af
NC
10721void
10722md_apply_fix3 (fixP, valP, seg)
b99bd4ef 10723 fixS * fixP;
94f592af 10724 valueT * valP;
b99bd4ef
NC
10725 segT seg;
10726{
94f592af 10727 offsetT value = * valP;
b99bd4ef
NC
10728 offsetT newval;
10729 unsigned int newimm;
10730 unsigned long temp;
10731 int sign;
10732 char * buf = fixP->fx_where + fixP->fx_frag->fr_literal;
10733 arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data;
10734
10735 assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
10736
10737 /* Note whether this will delete the relocation. */
10738#if 0
10739 /* Patch from REarnshaw to JDavis (disabled for the moment, since it
10740 doesn't work fully.) */
10741 if ((fixP->fx_addsy == 0 || symbol_constant_p (fixP->fx_addsy))
10742 && !fixP->fx_pcrel)
10743#else
10744 if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
10745#endif
10746 fixP->fx_done = 1;
10747
10748 /* If this symbol is in a different section then we need to leave it for
10749 the linker to deal with. Unfortunately, md_pcrel_from can't tell,
10750 so we have to undo it's effects here. */
10751 if (fixP->fx_pcrel)
10752 {
10753 if (fixP->fx_addsy != NULL
10754 && S_IS_DEFINED (fixP->fx_addsy)
10755 && S_GET_SEGMENT (fixP->fx_addsy) != seg)
10756 {
10757 if (target_oabi
10758 && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
10759 || fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
10760 ))
10761 value = 0;
10762 else
10763 value += md_pcrel_from (fixP);
10764 }
10765 }
10766
10767 /* Remember value for emit_reloc. */
10768 fixP->fx_addnumber = value;
10769
10770 switch (fixP->fx_r_type)
10771 {
10772 case BFD_RELOC_ARM_IMMEDIATE:
10773 newimm = validate_immediate (value);
10774 temp = md_chars_to_number (buf, INSN_SIZE);
10775
10776 /* If the instruction will fail, see if we can fix things up by
10777 changing the opcode. */
10778 if (newimm == (unsigned int) FAIL
10779 && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
10780 {
10781 as_bad_where (fixP->fx_file, fixP->fx_line,
10782 _("invalid constant (%lx) after fixup"),
10783 (unsigned long) value);
10784 break;
10785 }
10786
10787 newimm |= (temp & 0xfffff000);
10788 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
6189168b 10789 fixP->fx_done = 1;
b99bd4ef
NC
10790 break;
10791
10792 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
10793 {
10794 unsigned int highpart = 0;
10795 unsigned int newinsn = 0xe1a00000; /* nop. */
6189168b 10796
b99bd4ef
NC
10797 newimm = validate_immediate (value);
10798 temp = md_chars_to_number (buf, INSN_SIZE);
10799
10800 /* If the instruction will fail, see if we can fix things up by
10801 changing the opcode. */
10802 if (newimm == (unsigned int) FAIL
10803 && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
10804 {
10805 /* No ? OK - try using two ADD instructions to generate
10806 the value. */
10807 newimm = validate_immediate_twopart (value, & highpart);
10808
10809 /* Yes - then make sure that the second instruction is
10810 also an add. */
10811 if (newimm != (unsigned int) FAIL)
10812 newinsn = temp;
10813 /* Still No ? Try using a negated value. */
10814 else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
10815 temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
10816 /* Otherwise - give up. */
10817 else
10818 {
10819 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10820 _("unable to compute ADRL instructions for PC offset of 0x%lx"),
08df2379 10821 (long) value);
b99bd4ef
NC
10822 break;
10823 }
10824
10825 /* Replace the first operand in the 2nd instruction (which
10826 is the PC) with the destination register. We have
10827 already added in the PC in the first instruction and we
10828 do not want to do it again. */
10829 newinsn &= ~ 0xf0000;
10830 newinsn |= ((newinsn & 0x0f000) << 4);
10831 }
10832
10833 newimm |= (temp & 0xfffff000);
10834 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
10835
10836 highpart |= (newinsn & 0xfffff000);
10837 md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
10838 }
10839 break;
10840
10841 case BFD_RELOC_ARM_OFFSET_IMM:
10842 sign = value >= 0;
10843
10844 if (value < 0)
10845 value = - value;
10846
10847 if (validate_offset_imm (value, 0) == FAIL)
10848 {
10849 as_bad_where (fixP->fx_file, fixP->fx_line,
10850 _("bad immediate value for offset (%ld)"),
10851 (long) value);
10852 break;
10853 }
10854
10855 newval = md_chars_to_number (buf, INSN_SIZE);
10856 newval &= 0xff7ff000;
10857 newval |= value | (sign ? INDEX_UP : 0);
10858 md_number_to_chars (buf, newval, INSN_SIZE);
10859 break;
10860
10861 case BFD_RELOC_ARM_OFFSET_IMM8:
10862 case BFD_RELOC_ARM_HWLITERAL:
10863 sign = value >= 0;
10864
10865 if (value < 0)
10866 value = - value;
10867
10868 if (validate_offset_imm (value, 1) == FAIL)
10869 {
10870 if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
10871 as_bad_where (fixP->fx_file, fixP->fx_line,
10872 _("invalid literal constant: pool needs to be closer"));
10873 else
10874 as_bad (_("bad immediate value for half-word offset (%ld)"),
10875 (long) value);
10876 break;
10877 }
10878
10879 newval = md_chars_to_number (buf, INSN_SIZE);
10880 newval &= 0xff7ff0f0;
10881 newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
10882 md_number_to_chars (buf, newval, INSN_SIZE);
10883 break;
10884
10885 case BFD_RELOC_ARM_LITERAL:
10886 sign = value >= 0;
10887
10888 if (value < 0)
10889 value = - value;
10890
10891 if (validate_offset_imm (value, 0) == FAIL)
10892 {
10893 as_bad_where (fixP->fx_file, fixP->fx_line,
10894 _("invalid literal constant: pool needs to be closer"));
10895 break;
10896 }
10897
10898 newval = md_chars_to_number (buf, INSN_SIZE);
10899 newval &= 0xff7ff000;
10900 newval |= value | (sign ? INDEX_UP : 0);
10901 md_number_to_chars (buf, newval, INSN_SIZE);
10902 break;
10903
10904 case BFD_RELOC_ARM_SHIFT_IMM:
10905 newval = md_chars_to_number (buf, INSN_SIZE);
10906 if (((unsigned long) value) > 32
10907 || (value == 32
10908 && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
10909 {
10910 as_bad_where (fixP->fx_file, fixP->fx_line,
10911 _("shift expression is too large"));
10912 break;
10913 }
10914
10915 if (value == 0)
10916 /* Shifts of zero must be done as lsl. */
10917 newval &= ~0x60;
10918 else if (value == 32)
10919 value = 0;
10920 newval &= 0xfffff07f;
10921 newval |= (value & 0x1f) << 7;
10922 md_number_to_chars (buf, newval, INSN_SIZE);
10923 break;
10924
10925 case BFD_RELOC_ARM_SWI:
10926 if (arm_data->thumb_mode)
10927 {
10928 if (((unsigned long) value) > 0xff)
10929 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10930 _("invalid swi expression"));
b99bd4ef
NC
10931 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
10932 newval |= value;
10933 md_number_to_chars (buf, newval, THUMB_SIZE);
10934 }
10935 else
10936 {
10937 if (((unsigned long) value) > 0x00ffffff)
10938 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10939 _("invalid swi expression"));
b99bd4ef
NC
10940 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
10941 newval |= value;
10942 md_number_to_chars (buf, newval, INSN_SIZE);
10943 }
10944 break;
10945
10946 case BFD_RELOC_ARM_MULTI:
10947 if (((unsigned long) value) > 0xffff)
10948 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 10949 _("invalid expression in load/store multiple"));
b99bd4ef
NC
10950 newval = value | md_chars_to_number (buf, INSN_SIZE);
10951 md_number_to_chars (buf, newval, INSN_SIZE);
10952 break;
10953
10954 case BFD_RELOC_ARM_PCREL_BRANCH:
10955 newval = md_chars_to_number (buf, INSN_SIZE);
10956
10957 /* Sign-extend a 24-bit number. */
10958#define SEXT24(x) ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
10959
10960#ifdef OBJ_ELF
10961 if (! target_oabi)
10962 value = fixP->fx_offset;
10963#endif
10964
10965 /* We are going to store value (shifted right by two) in the
10966 instruction, in a 24 bit, signed field. Thus we need to check
10967 that none of the top 8 bits of the shifted value (top 7 bits of
10968 the unshifted, unsigned value) are set, or that they are all set. */
10969 if ((value & ~ ((offsetT) 0x1ffffff)) != 0
10970 && ((value & ~ ((offsetT) 0x1ffffff)) != ~ ((offsetT) 0x1ffffff)))
10971 {
10972#ifdef OBJ_ELF
10973 /* Normally we would be stuck at this point, since we cannot store
10974 the absolute address that is the destination of the branch in the
10975 24 bits of the branch instruction. If however, we happen to know
10976 that the destination of the branch is in the same section as the
10977 branch instruciton itself, then we can compute the relocation for
10978 ourselves and not have to bother the linker with it.
10979
10980 FIXME: The tests for OBJ_ELF and ! target_oabi are only here
10981 because I have not worked out how to do this for OBJ_COFF or
10982 target_oabi. */
10983 if (! target_oabi
10984 && fixP->fx_addsy != NULL
10985 && S_IS_DEFINED (fixP->fx_addsy)
10986 && S_GET_SEGMENT (fixP->fx_addsy) == seg)
10987 {
10988 /* Get pc relative value to go into the branch. */
94f592af 10989 value = * valP;
b99bd4ef
NC
10990
10991 /* Permit a backward branch provided that enough bits
10992 are set. Allow a forwards branch, provided that
10993 enough bits are clear. */
10994 if ( (value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff)
10995 || (value & ~ ((offsetT) 0x1ffffff)) == 0)
10996 fixP->fx_done = 1;
10997 }
10998
10999 if (! fixP->fx_done)
11000#endif
11001 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11002 _("GAS can't handle same-section branch dest >= 0x04000000"));
b99bd4ef
NC
11003 }
11004
11005 value >>= 2;
11006 value += SEXT24 (newval);
11007
11008 if ( (value & ~ ((offsetT) 0xffffff)) != 0
11009 && ((value & ~ ((offsetT) 0xffffff)) != ~ ((offsetT) 0xffffff)))
11010 as_bad_where (fixP->fx_file, fixP->fx_line,
11011 _("out of range branch"));
11012
11013 newval = (value & 0x00ffffff) | (newval & 0xff000000);
11014 md_number_to_chars (buf, newval, INSN_SIZE);
11015 break;
11016
11017 case BFD_RELOC_ARM_PCREL_BLX:
11018 {
11019 offsetT hbit;
11020 newval = md_chars_to_number (buf, INSN_SIZE);
11021
11022#ifdef OBJ_ELF
11023 if (! target_oabi)
11024 value = fixP->fx_offset;
11025#endif
11026 hbit = (value >> 1) & 1;
11027 value = (value >> 2) & 0x00ffffff;
11028 value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
11029 newval = value | (newval & 0xfe000000) | (hbit << 24);
11030 md_number_to_chars (buf, newval, INSN_SIZE);
11031 }
11032 break;
11033
11034 case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
11035 newval = md_chars_to_number (buf, THUMB_SIZE);
11036 {
11037 addressT diff = (newval & 0xff) << 1;
11038 if (diff & 0x100)
11039 diff |= ~0xff;
11040
11041 value += diff;
11042 if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
11043 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11044 _("branch out of range"));
b99bd4ef
NC
11045 newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
11046 }
11047 md_number_to_chars (buf, newval, THUMB_SIZE);
11048 break;
11049
11050 case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch. */
11051 newval = md_chars_to_number (buf, THUMB_SIZE);
11052 {
11053 addressT diff = (newval & 0x7ff) << 1;
11054 if (diff & 0x800)
11055 diff |= ~0x7ff;
11056
11057 value += diff;
11058 if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
11059 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11060 _("branch out of range"));
b99bd4ef
NC
11061 newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
11062 }
11063 md_number_to_chars (buf, newval, THUMB_SIZE);
11064 break;
11065
11066 case BFD_RELOC_THUMB_PCREL_BLX:
11067 case BFD_RELOC_THUMB_PCREL_BRANCH23:
11068 {
11069 offsetT newval2;
11070 addressT diff;
11071
11072 newval = md_chars_to_number (buf, THUMB_SIZE);
11073 newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
11074 diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
11075 if (diff & 0x400000)
11076 diff |= ~0x3fffff;
11077#ifdef OBJ_ELF
11078 value = fixP->fx_offset;
11079#endif
11080 value += diff;
c62e1cc3 11081
b99bd4ef
NC
11082 if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
11083 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11084 _("branch with link out of range"));
b99bd4ef
NC
11085
11086 newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
11087 newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
11088 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
c62e1cc3
NC
11089 /* For a BLX instruction, make sure that the relocation is rounded up
11090 to a word boundary. This follows the semantics of the instruction
11091 which specifies that bit 1 of the target address will come from bit
11092 1 of the base address. */
11093 newval2 = (newval2 + 1) & ~ 1;
b99bd4ef
NC
11094 md_number_to_chars (buf, newval, THUMB_SIZE);
11095 md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
11096 }
11097 break;
11098
11099 case BFD_RELOC_8:
11100 if (fixP->fx_done || fixP->fx_pcrel)
11101 md_number_to_chars (buf, value, 1);
11102#ifdef OBJ_ELF
11103 else if (!target_oabi)
11104 {
11105 value = fixP->fx_offset;
11106 md_number_to_chars (buf, value, 1);
11107 }
11108#endif
11109 break;
11110
11111 case BFD_RELOC_16:
11112 if (fixP->fx_done || fixP->fx_pcrel)
11113 md_number_to_chars (buf, value, 2);
11114#ifdef OBJ_ELF
11115 else if (!target_oabi)
11116 {
11117 value = fixP->fx_offset;
11118 md_number_to_chars (buf, value, 2);
11119 }
11120#endif
11121 break;
11122
11123#ifdef OBJ_ELF
11124 case BFD_RELOC_ARM_GOT32:
11125 case BFD_RELOC_ARM_GOTOFF:
11126 md_number_to_chars (buf, 0, 4);
11127 break;
11128#endif
11129
11130 case BFD_RELOC_RVA:
11131 case BFD_RELOC_32:
11132 if (fixP->fx_done || fixP->fx_pcrel)
11133 md_number_to_chars (buf, value, 4);
11134#ifdef OBJ_ELF
11135 else if (!target_oabi)
11136 {
11137 value = fixP->fx_offset;
11138 md_number_to_chars (buf, value, 4);
11139 }
11140#endif
11141 break;
11142
11143#ifdef OBJ_ELF
11144 case BFD_RELOC_ARM_PLT32:
11145 /* It appears the instruction is fully prepared at this point. */
11146 break;
11147#endif
11148
b99bd4ef
NC
11149 case BFD_RELOC_ARM_CP_OFF_IMM:
11150 sign = value >= 0;
11151 if (value < -1023 || value > 1023 || (value & 3))
11152 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11153 _("illegal value for co-processor offset"));
b99bd4ef
NC
11154 if (value < 0)
11155 value = -value;
11156 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
11157 newval |= (value >> 2) | (sign ? INDEX_UP : 0);
11158 md_number_to_chars (buf, newval, INSN_SIZE);
11159 break;
11160
e16bb312
NC
11161 case BFD_RELOC_ARM_CP_OFF_IMM_S2:
11162 sign = value >= 0;
11163 if (value < -255 || value > 255)
11164 as_bad_where (fixP->fx_file, fixP->fx_line,
11165 _("Illegal value for co-processor offset"));
11166 if (value < 0)
11167 value = -value;
11168 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
11169 newval |= value | (sign ? INDEX_UP : 0);
11170 md_number_to_chars (buf, newval , INSN_SIZE);
11171 break;
11172
b99bd4ef
NC
11173 case BFD_RELOC_ARM_THUMB_OFFSET:
11174 newval = md_chars_to_number (buf, THUMB_SIZE);
11175 /* Exactly what ranges, and where the offset is inserted depends
11176 on the type of instruction, we can establish this from the
11177 top 4 bits. */
11178 switch (newval >> 12)
11179 {
11180 case 4: /* PC load. */
11181 /* Thumb PC loads are somewhat odd, bit 1 of the PC is
11182 forced to zero for these loads, so we will need to round
11183 up the offset if the instruction address is not word
11184 aligned (since the final address produced must be, and
11185 we can only describe word-aligned immediate offsets). */
11186
11187 if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3)
11188 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11189 _("invalid offset, target not word aligned (0x%08X)"),
b99bd4ef
NC
11190 (unsigned int) (fixP->fx_frag->fr_address
11191 + fixP->fx_where + value));
11192
11193 if ((value + 2) & ~0x3fe)
11194 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11195 _("invalid offset, value too big (0x%08lX)"),
11196 (long) value);
b99bd4ef
NC
11197
11198 /* Round up, since pc will be rounded down. */
11199 newval |= (value + 2) >> 2;
11200 break;
11201
11202 case 9: /* SP load/store. */
11203 if (value & ~0x3fc)
11204 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11205 _("invalid offset, value too big (0x%08lX)"),
11206 (long) value);
b99bd4ef
NC
11207 newval |= value >> 2;
11208 break;
11209
11210 case 6: /* Word load/store. */
11211 if (value & ~0x7c)
11212 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11213 _("invalid offset, value too big (0x%08lX)"),
11214 (long) value);
b99bd4ef
NC
11215 newval |= value << 4; /* 6 - 2. */
11216 break;
11217
11218 case 7: /* Byte load/store. */
11219 if (value & ~0x1f)
11220 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11221 _("invalid offset, value too big (0x%08lX)"),
11222 (long) value);
b99bd4ef
NC
11223 newval |= value << 6;
11224 break;
11225
11226 case 8: /* Halfword load/store. */
11227 if (value & ~0x3e)
11228 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
11229 _("invalid offset, value too big (0x%08lX)"),
11230 (long) value);
b99bd4ef
NC
11231 newval |= value << 5; /* 6 - 1. */
11232 break;
11233
11234 default:
11235 as_bad_where (fixP->fx_file, fixP->fx_line,
11236 "Unable to process relocation for thumb opcode: %lx",
11237 (unsigned long) newval);
11238 break;
11239 }
11240 md_number_to_chars (buf, newval, THUMB_SIZE);
11241 break;
11242
11243 case BFD_RELOC_ARM_THUMB_ADD:
11244 /* This is a complicated relocation, since we use it for all of
11245 the following immediate relocations:
11246
11247 3bit ADD/SUB
11248 8bit ADD/SUB
11249 9bit ADD/SUB SP word-aligned
11250 10bit ADD PC/SP word-aligned
11251
11252 The type of instruction being processed is encoded in the
11253 instruction field:
11254
11255 0x8000 SUB
11256 0x00F0 Rd
11257 0x000F Rs
11258 */
11259 newval = md_chars_to_number (buf, THUMB_SIZE);
11260 {
11261 int rd = (newval >> 4) & 0xf;
11262 int rs = newval & 0xf;
11263 int subtract = newval & 0x8000;
11264
11265 if (rd == REG_SP)
11266 {
11267 if (value & ~0x1fc)
11268 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11269 _("invalid immediate for stack address calculation"));
b99bd4ef
NC
11270 newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
11271 newval |= value >> 2;
11272 }
11273 else if (rs == REG_PC || rs == REG_SP)
11274 {
11275 if (subtract ||
11276 value & ~0x3fc)
11277 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11278 _("invalid immediate for address calculation (value = 0x%08lX)"),
b99bd4ef
NC
11279 (unsigned long) value);
11280 newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
11281 newval |= rd << 8;
11282 newval |= value >> 2;
11283 }
11284 else if (rs == rd)
11285 {
11286 if (value & ~0xff)
11287 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11288 _("invalid 8bit immediate"));
b99bd4ef
NC
11289 newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
11290 newval |= (rd << 8) | value;
11291 }
11292 else
11293 {
11294 if (value & ~0x7)
11295 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11296 _("invalid 3bit immediate"));
b99bd4ef
NC
11297 newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
11298 newval |= rd | (rs << 3) | (value << 6);
11299 }
11300 }
11301 md_number_to_chars (buf, newval, THUMB_SIZE);
11302 break;
11303
11304 case BFD_RELOC_ARM_THUMB_IMM:
11305 newval = md_chars_to_number (buf, THUMB_SIZE);
11306 switch (newval >> 11)
11307 {
11308 case 0x04: /* 8bit immediate MOV. */
11309 case 0x05: /* 8bit immediate CMP. */
11310 if (value < 0 || value > 255)
11311 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11312 _("invalid immediate: %ld is too large"),
b99bd4ef
NC
11313 (long) value);
11314 newval |= value;
11315 break;
11316
11317 default:
11318 abort ();
11319 }
11320 md_number_to_chars (buf, newval, THUMB_SIZE);
11321 break;
11322
11323 case BFD_RELOC_ARM_THUMB_SHIFT:
11324 /* 5bit shift value (0..31). */
11325 if (value < 0 || value > 31)
11326 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11327 _("illegal Thumb shift value: %ld"), (long) value);
b99bd4ef
NC
11328 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
11329 newval |= value << 6;
11330 md_number_to_chars (buf, newval, THUMB_SIZE);
11331 break;
11332
11333 case BFD_RELOC_VTABLE_INHERIT:
11334 case BFD_RELOC_VTABLE_ENTRY:
11335 fixP->fx_done = 0;
94f592af 11336 return;
b99bd4ef
NC
11337
11338 case BFD_RELOC_NONE:
11339 default:
11340 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11341 _("bad relocation fixup type (%d)"), fixP->fx_r_type);
b99bd4ef 11342 }
b99bd4ef
NC
11343}
11344
11345/* Translate internal representation of relocation info to BFD target
11346 format. */
11347
11348arelent *
11349tc_gen_reloc (section, fixp)
11350 asection * section ATTRIBUTE_UNUSED;
11351 fixS * fixp;
11352{
11353 arelent * reloc;
11354 bfd_reloc_code_real_type code;
11355
11356 reloc = (arelent *) xmalloc (sizeof (arelent));
11357
11358 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
11359 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
11360 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
11361
11362 /* @@ Why fx_addnumber sometimes and fx_offset other times? */
11363#ifndef OBJ_ELF
11364 if (fixp->fx_pcrel == 0)
11365 reloc->addend = fixp->fx_offset;
11366 else
11367 reloc->addend = fixp->fx_offset = reloc->address;
11368#else /* OBJ_ELF */
11369 reloc->addend = fixp->fx_offset;
11370#endif
11371
11372 switch (fixp->fx_r_type)
11373 {
11374 case BFD_RELOC_8:
11375 if (fixp->fx_pcrel)
11376 {
11377 code = BFD_RELOC_8_PCREL;
11378 break;
11379 }
11380
11381 case BFD_RELOC_16:
11382 if (fixp->fx_pcrel)
11383 {
11384 code = BFD_RELOC_16_PCREL;
11385 break;
11386 }
11387
11388 case BFD_RELOC_32:
11389 if (fixp->fx_pcrel)
11390 {
11391 code = BFD_RELOC_32_PCREL;
11392 break;
11393 }
11394
11395 case BFD_RELOC_ARM_PCREL_BRANCH:
11396 case BFD_RELOC_ARM_PCREL_BLX:
11397 case BFD_RELOC_RVA:
11398 case BFD_RELOC_THUMB_PCREL_BRANCH9:
11399 case BFD_RELOC_THUMB_PCREL_BRANCH12:
11400 case BFD_RELOC_THUMB_PCREL_BRANCH23:
11401 case BFD_RELOC_THUMB_PCREL_BLX:
11402 case BFD_RELOC_VTABLE_ENTRY:
11403 case BFD_RELOC_VTABLE_INHERIT:
11404 code = fixp->fx_r_type;
11405 break;
11406
11407 case BFD_RELOC_ARM_LITERAL:
11408 case BFD_RELOC_ARM_HWLITERAL:
3d0c9500
NC
11409 /* If this is called then the a literal has
11410 been referenced across a section boundary. */
b99bd4ef 11411 as_bad_where (fixp->fx_file, fixp->fx_line,
61b5f74b 11412 _("literal referenced across section boundary"));
b99bd4ef
NC
11413 return NULL;
11414
11415#ifdef OBJ_ELF
11416 case BFD_RELOC_ARM_GOT32:
11417 case BFD_RELOC_ARM_GOTOFF:
11418 case BFD_RELOC_ARM_PLT32:
11419 code = fixp->fx_r_type;
11420 break;
11421#endif
11422
11423 case BFD_RELOC_ARM_IMMEDIATE:
11424 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 11425 _("internal relocation (type: IMMEDIATE) not fixed up"));
b99bd4ef
NC
11426 return NULL;
11427
11428 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
11429 as_bad_where (fixp->fx_file, fixp->fx_line,
11430 _("ADRL used for a symbol not defined in the same file"));
11431 return NULL;
11432
11433 case BFD_RELOC_ARM_OFFSET_IMM:
11434 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 11435 _("internal_relocation (type: OFFSET_IMM) not fixed up"));
b99bd4ef
NC
11436 return NULL;
11437
11438 default:
11439 {
11440 char * type;
11441
11442 switch (fixp->fx_r_type)
11443 {
b99bd4ef
NC
11444 case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break;
11445 case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break;
11446 case BFD_RELOC_ARM_SWI: type = "SWI"; break;
11447 case BFD_RELOC_ARM_MULTI: type = "MULTI"; break;
11448 case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break;
11449 case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break;
11450 case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break;
11451 case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break;
11452 case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
11453 default: type = _("<unknown>"); break;
11454 }
11455 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 11456 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
11457 type);
11458 return NULL;
11459 }
11460 }
11461
11462#ifdef OBJ_ELF
8df7094c 11463 if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
b99bd4ef
NC
11464 && GOT_symbol
11465 && fixp->fx_addsy == GOT_symbol)
11466 {
11467 code = BFD_RELOC_ARM_GOTPC;
11468 reloc->addend = fixp->fx_offset = reloc->address;
11469 }
11470#endif
11471
11472 reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
11473
11474 if (reloc->howto == NULL)
11475 {
11476 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 11477 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
11478 bfd_get_reloc_code_name (code));
11479 return NULL;
11480 }
11481
11482 /* HACK: Since arm ELF uses Rel instead of Rela, encode the
11483 vtable entry to be used in the relocation's section offset. */
11484 if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
11485 reloc->address = fixp->fx_offset;
11486
11487 return reloc;
11488}
11489
11490int
11491md_estimate_size_before_relax (fragP, segtype)
11492 fragS * fragP ATTRIBUTE_UNUSED;
11493 segT segtype ATTRIBUTE_UNUSED;
11494{
11495 as_fatal (_("md_estimate_size_before_relax\n"));
11496 return 1;
11497}
11498
11499static void
f03698e6
RE
11500output_inst (str)
11501 const char *str;
b99bd4ef
NC
11502{
11503 char * to = NULL;
11504
11505 if (inst.error)
11506 {
f03698e6 11507 as_bad ("%s -- `%s'", inst.error, str);
b99bd4ef
NC
11508 return;
11509 }
11510
11511 to = frag_more (inst.size);
11512
11513 if (thumb_mode && (inst.size > THUMB_SIZE))
11514 {
11515 assert (inst.size == (2 * THUMB_SIZE));
11516 md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE);
11517 md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE);
11518 }
11519 else if (inst.size > INSN_SIZE)
11520 {
11521 assert (inst.size == (2 * INSN_SIZE));
11522 md_number_to_chars (to, inst.instruction, INSN_SIZE);
11523 md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
11524 }
11525 else
11526 md_number_to_chars (to, inst.instruction, inst.size);
11527
11528 if (inst.reloc.type != BFD_RELOC_NONE)
11529 fix_new_arm (frag_now, to - frag_now->fr_literal,
11530 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
11531 inst.reloc.type);
11532
11533#ifdef OBJ_ELF
11534 dwarf2_emit_insn (inst.size);
11535#endif
11536}
11537
11538void
11539md_assemble (str)
11540 char * str;
11541{
6c43fab6
RE
11542 char c;
11543 char *p;
11544 char *start;
b99bd4ef
NC
11545
11546 /* Align the instruction.
11547 This may not be the right thing to do but ... */
11548#if 0
11549 arm_align (2, 0);
11550#endif
b99bd4ef
NC
11551
11552 /* Align the previous label if needed. */
11553 if (last_label_seen != NULL)
11554 {
11555 symbol_set_frag (last_label_seen, frag_now);
11556 S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
11557 S_SET_SEGMENT (last_label_seen, now_seg);
11558 }
11559
11560 memset (&inst, '\0', sizeof (inst));
11561 inst.reloc.type = BFD_RELOC_NONE;
11562
11563 skip_whitespace (str);
11564
11565 /* Scan up to the end of the op-code, which must end in white space or
11566 end of string. */
11567 for (start = p = str; *p != '\0'; p++)
11568 if (*p == ' ')
11569 break;
11570
11571 if (p == str)
11572 {
f03698e6 11573 as_bad (_("no operator -- statement `%s'\n"), str);
b99bd4ef
NC
11574 return;
11575 }
11576
11577 if (thumb_mode)
11578 {
05d2d07e 11579 const struct thumb_opcode * opcode;
b99bd4ef
NC
11580
11581 c = *p;
11582 *p = '\0';
05d2d07e 11583 opcode = (const struct thumb_opcode *) hash_find (arm_tops_hsh, str);
b99bd4ef
NC
11584 *p = c;
11585
11586 if (opcode)
11587 {
11588 /* Check that this instruction is supported for this CPU. */
90e4755a 11589 if (thumb_mode == 1 && (opcode->variant & cpu_variant) == 0)
b99bd4ef 11590 {
f03698e6 11591 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
11592 return;
11593 }
11594
11595 inst.instruction = opcode->value;
11596 inst.size = opcode->size;
11597 (*opcode->parms) (p);
f03698e6 11598 output_inst (str);
b99bd4ef
NC
11599 return;
11600 }
11601 }
11602 else
11603 {
05d2d07e 11604 const struct asm_opcode * opcode;
b99bd4ef 11605
90e4755a
RE
11606 c = *p;
11607 *p = '\0';
6c43fab6 11608 opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, str);
90e4755a 11609 *p = c;
b99bd4ef 11610
90e4755a 11611 if (opcode)
b99bd4ef 11612 {
90e4755a
RE
11613 /* Check that this instruction is supported for this CPU. */
11614 if ((opcode->variant & cpu_variant) == 0)
b99bd4ef 11615 {
f03698e6 11616 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
11617 return;
11618 }
11619
90e4755a
RE
11620 inst.instruction = opcode->value;
11621 inst.size = INSN_SIZE;
f2b7cb0a 11622 (*opcode->parms) (p);
f03698e6 11623 output_inst (str);
90e4755a 11624 return;
b99bd4ef
NC
11625 }
11626 }
11627
11628 /* It wasn't an instruction, but it might be a register alias of the form
11629 alias .req reg. */
6c43fab6
RE
11630 if (create_register_alias (str, p))
11631 return;
b99bd4ef 11632
b99bd4ef
NC
11633 as_bad (_("bad instruction `%s'"), start);
11634}
11635
11636/* md_parse_option
11637 Invocation line includes a switch not recognized by the base assembler.
cc8a6dd0 11638 See if it's a processor-specific option.
03b1477f
RE
11639
11640 This routine is somewhat complicated by the need for backwards
11641 compatibility (since older releases of gcc can't be changed).
11642 The new options try to make the interface as compatible as
11643 possible with GCC.
11644
11645 New options (supported) are:
11646
11647 -mcpu=<cpu name> Assemble for selected processor
11648 -march=<architecture name> Assemble for selected architecture
11649 -mfpu=<fpu architecture> Assemble for selected FPU.
11650 -EB/-mbig-endian Big-endian
11651 -EL/-mlittle-endian Little-endian
11652 -k Generate PIC code
11653 -mthumb Start in Thumb mode
11654 -mthumb-interwork Code supports ARM/Thumb interworking
11655
3d0c9500 11656 For now we will also provide support for:
03b1477f
RE
11657
11658 -mapcs-32 32-bit Program counter
11659 -mapcs-26 26-bit Program counter
11660 -macps-float Floats passed in FP registers
11661 -mapcs-reentrant Reentrant code
11662 -matpcs
11663 (sometime these will probably be replaced with -mapcs=<list of options>
11664 and -matpcs=<list of options>)
11665
11666 The remaining options are only supported for back-wards compatibility.
b99bd4ef
NC
11667 Cpu variants, the arm part is optional:
11668 -m[arm]1 Currently not supported.
11669 -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor
11670 -m[arm]3 Arm 3 processor
11671 -m[arm]6[xx], Arm 6 processors
11672 -m[arm]7[xx][t][[d]m] Arm 7 processors
11673 -m[arm]8[10] Arm 8 processors
11674 -m[arm]9[20][tdmi] Arm 9 processors
11675 -mstrongarm[110[0]] StrongARM processors
11676 -mxscale XScale processors
11677 -m[arm]v[2345[t[e]]] Arm architectures
11678 -mall All (except the ARM1)
11679 FP variants:
11680 -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
11681 -mfpe-old (No float load/store multiples)
bfae80f2
RE
11682 -mvfpxd VFP Single precision
11683 -mvfp All VFP
b99bd4ef 11684 -mno-fpu Disable all floating point instructions
b99bd4ef 11685
03b1477f
RE
11686 The following CPU names are recognized:
11687 arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
11688 arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
11689 arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
11690 arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
11691 arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
11692 arm10t arm10e, arm1020t, arm1020e, arm10200e,
11693 strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
11694
11695 */
11696
5a38dc70 11697const char * md_shortopts = "m:k";
03b1477f 11698
b99bd4ef
NC
11699#ifdef ARM_BI_ENDIAN
11700#define OPTION_EB (OPTION_MD_BASE + 0)
b99bd4ef 11701#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 11702#else
21f0f23a
RE
11703#if TARGET_BYTES_BIG_ENDIAN
11704#define OPTION_EB (OPTION_MD_BASE + 0)
21f0f23a
RE
11705#else
11706#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 11707#endif
ce058b6c 11708#endif
03b1477f
RE
11709
11710struct option md_longopts[] =
11711{
11712#ifdef OPTION_EB
11713 {"EB", no_argument, NULL, OPTION_EB},
11714#endif
11715#ifdef OPTION_EL
11716 {"EL", no_argument, NULL, OPTION_EL},
b99bd4ef
NC
11717#endif
11718 {NULL, no_argument, NULL, 0}
11719};
11720
11721size_t md_longopts_size = sizeof (md_longopts);
11722
03b1477f 11723struct arm_option_table
b99bd4ef 11724{
03b1477f
RE
11725 char *option; /* Option name to match. */
11726 char *help; /* Help information. */
11727 int *var; /* Variable to change. */
11728 int value; /* What to change it to. */
11729 char *deprecated; /* If non-null, print this message. */
11730};
b99bd4ef 11731
cc8a6dd0 11732struct arm_option_table arm_opts[] =
03b1477f
RE
11733{
11734 {"k", N_("generate PIC code"), &pic_code, 1, NULL},
11735 {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL},
11736 {"mthumb-interwork", N_("support ARM/Thumb interworking"),
11737 &support_interwork, 1, NULL},
11738 {"moabi", N_("use old ABI (ELF only)"), &target_oabi, 1, NULL},
11739 {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
11740 {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
11741 {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
11742 1, NULL},
11743 {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
11744 {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
11745 {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
11746 {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 1,
11747 NULL},
11748
11749 /* These are recognized by the assembler, but have no affect on code. */
11750 {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
11751 {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
11752
11753 /* DON'T add any new processors to this list -- we want the whole list
11754 to go away... Add them to the processors table instead. */
11755 {"marm1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
11756 {"m1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
11757 {"marm2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
11758 {"m2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
11759 {"marm250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
11760 {"m250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
11761 {"marm3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
11762 {"m3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
11763 {"marm6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
11764 {"m6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
11765 {"marm600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
11766 {"m600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
11767 {"marm610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
11768 {"m610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
11769 {"marm620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
11770 {"m620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
11771 {"marm7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
11772 {"m7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
11773 {"marm70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
11774 {"m70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
11775 {"marm700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
11776 {"m700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
11777 {"marm700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
11778 {"m700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
11779 {"marm710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
11780 {"m710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
11781 {"marm710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
11782 {"m710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
11783 {"marm720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
11784 {"m720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
11785 {"marm7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
11786 {"m7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
11787 {"marm7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
11788 {"m7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
11789 {"marm7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
11790 {"m7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
11791 {"marm7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
11792 {"m7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
11793 {"marm7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
11794 {"m7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
11795 {"marm7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
11796 {"m7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
11797 {"marm7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
11798 {"m7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
11799 {"marm7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
11800 {"m7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
11801 {"marm7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11802 {"m7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11803 {"marm7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11804 {"m7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
11805 {"marm710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
11806 {"m710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
11807 {"marm720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
11808 {"m720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
11809 {"marm740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
11810 {"m740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
11811 {"marm8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
11812 {"m8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
11813 {"marm810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
11814 {"m810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
11815 {"marm9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
11816 {"m9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
11817 {"marm9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
11818 {"m9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
11819 {"marm920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
11820 {"m920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
11821 {"marm940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
11822 {"m940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
11823 {"mstrongarm", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=strongarm")},
11824 {"mstrongarm110", NULL, &legacy_cpu, ARM_ARCH_V4,
11825 N_("use -mcpu=strongarm110")},
11826 {"mstrongarm1100", NULL, &legacy_cpu, ARM_ARCH_V4,
11827 N_("use -mcpu=strongarm1100")},
11828 {"mstrongarm1110", NULL, &legacy_cpu, ARM_ARCH_V4,
11829 N_("use -mcpu=strongarm1110")},
11830 {"mxscale", NULL, &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
e16bb312 11831 {"miwmmxt", NULL, &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
03b1477f
RE
11832 {"mall", NULL, &legacy_cpu, ARM_ANY, N_("use -mcpu=all")},
11833
11834 /* Architecture variants -- don't add any more to this list either. */
11835 {"mv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
11836 {"marmv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
11837 {"mv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
11838 {"marmv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
11839 {"mv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
11840 {"marmv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
11841 {"mv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
11842 {"marmv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
11843 {"mv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
11844 {"marmv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
11845 {"mv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
11846 {"marmv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
11847 {"mv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
11848 {"marmv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
11849 {"mv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
11850 {"marmv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
11851 {"mv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
11852 {"marmv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
11853
11854 /* Floating point variants -- don't add any more to this list either. */
11855 {"mfpe-old", NULL, &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
11856 {"mfpa10", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
11857 {"mfpa11", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
11858 {"mno-fpu", NULL, &legacy_fpu, 0,
11859 N_("use either -mfpu=softfpa or -mfpu=softvfp")},
11860
11861 {NULL, NULL, NULL, 0, NULL}
11862};
21f0f23a 11863
03b1477f
RE
11864struct arm_cpu_option_table
11865{
11866 char *name;
11867 int value;
11868 /* For some CPUs we assume an FPU unless the user explicitly sets
11869 -mfpu=... */
11870 int default_fpu;
11871};
11872
11873/* This list should, at a minimum, contain all the cpu names
11874 recognized by GCC. */
11875static struct arm_cpu_option_table arm_cpus[] =
11876{
11877 {"all", ARM_ANY, FPU_ARCH_FPA},
11878 {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA},
11879 {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA},
11880 {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA},
11881 {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA},
11882 {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA},
11883 {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA},
11884 {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA},
11885 {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA},
11886 {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA},
11887 {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA},
11888 {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA},
11889 {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA},
11890 {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA},
11891 {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA},
11892 {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA},
11893 {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA},
11894 {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA},
11895 {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA},
11896 {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA},
11897 {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11898 {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA},
11899 {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11900 {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11901 {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA},
11902 {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA},
11903 {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA},
11904 {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA},
11905 {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11906 {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
11907 {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA},
11908 {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA},
11909 {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA},
11910 {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA},
11911 {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA},
11912 {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA},
11913 {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA},
11914 {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA},
11915 {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA},
11916 {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11917 {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11918 {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11919 {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
11920 /* For V5 or later processors we default to using VFP; but the user
11921 should really set the FPU type explicitly. */
11922 {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
11923 {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
ea6ef066 11924 {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
03b1477f
RE
11925 {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
11926 {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11927 {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
11928 {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11929 {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
11930 {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11931 {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11932 {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
11933 {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
11934 /* ??? XSCALE is really an architecture. */
11935 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
5a6c6817 11936 /* ??? iwmmxt is not a processor. */
e16bb312 11937 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2},
03b1477f
RE
11938 {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
11939 /* Maverick */
11940 {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_NONE},
11941 {NULL, 0, 0}
11942};
cc8a6dd0 11943
03b1477f
RE
11944struct arm_arch_option_table
11945{
11946 char *name;
11947 int value;
11948 int default_fpu;
11949};
11950
11951/* This list should, at a minimum, contain all the architecture names
11952 recognized by GCC. */
11953static struct arm_arch_option_table arm_archs[] =
11954{
11955 {"all", ARM_ANY, FPU_ARCH_FPA},
11956 {"armv1", ARM_ARCH_V1, FPU_ARCH_FPA},
11957 {"armv2", ARM_ARCH_V2, FPU_ARCH_FPA},
11958 {"armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA},
11959 {"armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA},
11960 {"armv3", ARM_ARCH_V3, FPU_ARCH_FPA},
11961 {"armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA},
11962 {"armv4", ARM_ARCH_V4, FPU_ARCH_FPA},
11963 {"armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA},
11964 {"armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA},
11965 {"armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA},
11966 {"armv5", ARM_ARCH_V5, FPU_ARCH_VFP},
11967 {"armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP},
11968 {"armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP},
11969 {"armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP},
11970 {"armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP},
ea6ef066 11971 {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP},
03b1477f 11972 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP},
8266886e 11973 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
03b1477f
RE
11974 {NULL, 0, 0}
11975};
11976
11977/* ISA extensions in the co-processor space. */
11978struct arm_arch_extension_table
11979{
11980 char *name;
11981 int value;
11982};
11983
11984static struct arm_arch_extension_table arm_extensions[] =
11985{
11986 {"maverick", ARM_CEXT_MAVERICK},
11987 {"xscale", ARM_CEXT_XSCALE},
e16bb312 11988 {"iwmmxt", ARM_CEXT_IWMMXT},
03b1477f
RE
11989 {NULL, 0}
11990};
b99bd4ef 11991
03b1477f
RE
11992struct arm_fpu_option_table
11993{
11994 char *name;
11995 int value;
11996};
11997
11998/* This list should, at a minimum, contain all the fpu names
11999 recognized by GCC. */
12000static struct arm_fpu_option_table arm_fpus[] =
12001{
12002 {"softfpa", FPU_NONE},
12003 {"fpe", FPU_ARCH_FPE},
d193a22a
RE
12004 {"fpe2", FPU_ARCH_FPE},
12005 {"fpe3", FPU_ARCH_FPA}, /* Third release supports LFM/SFM. */
03b1477f
RE
12006 {"fpa", FPU_ARCH_FPA},
12007 {"fpa10", FPU_ARCH_FPA},
12008 {"fpa11", FPU_ARCH_FPA},
12009 {"arm7500fe", FPU_ARCH_FPA},
12010 {"softvfp", FPU_ARCH_VFP},
12011 {"softvfp+vfp", FPU_ARCH_VFP_V2},
12012 {"vfp", FPU_ARCH_VFP_V2},
12013 {"vfp9", FPU_ARCH_VFP_V2},
12014 {"vfp10", FPU_ARCH_VFP_V2},
12015 {"vfp10-r0", FPU_ARCH_VFP_V1},
12016 {"vfpxd", FPU_ARCH_VFP_V1xD},
12017 {"arm1020t", FPU_ARCH_VFP_V1},
12018 {"arm1020e", FPU_ARCH_VFP_V2},
12019 {NULL, 0}
12020};
12021
12022struct arm_long_option_table
12023{
12024 char *option; /* Substring to match. */
12025 char *help; /* Help information. */
12026 int (*func) PARAMS ((char *subopt)); /* Function to decode sub-option. */
12027 char *deprecated; /* If non-null, print this message. */
12028};
12029
12030static int
12031arm_parse_extension (str, opt_p)
12032 char *str;
12033 int *opt_p;
12034{
12035 while (str != NULL && *str != 0)
12036 {
12037 struct arm_arch_extension_table *opt;
12038 char *ext;
12039 int optlen;
12040
12041 if (*str != '+')
b99bd4ef 12042 {
03b1477f
RE
12043 as_bad (_("invalid architectural extension"));
12044 return 0;
12045 }
b99bd4ef 12046
03b1477f
RE
12047 str++;
12048 ext = strchr (str, '+');
b99bd4ef 12049
03b1477f
RE
12050 if (ext != NULL)
12051 optlen = ext - str;
12052 else
12053 optlen = strlen (str);
b99bd4ef 12054
03b1477f
RE
12055 if (optlen == 0)
12056 {
12057 as_bad (_("missing architectural extension"));
12058 return 0;
12059 }
b99bd4ef 12060
03b1477f
RE
12061 for (opt = arm_extensions; opt->name != NULL; opt++)
12062 if (strncmp (opt->name, str, optlen) == 0)
12063 {
12064 *opt_p |= opt->value;
12065 break;
12066 }
bfae80f2 12067
03b1477f
RE
12068 if (opt->name == NULL)
12069 {
12070 as_bad (_("unknown architectural extnsion `%s'"), str);
12071 return 0;
12072 }
b99bd4ef 12073
03b1477f
RE
12074 str = ext;
12075 };
b99bd4ef 12076
03b1477f
RE
12077 return 1;
12078}
b99bd4ef 12079
03b1477f
RE
12080static int
12081arm_parse_cpu (str)
12082 char *str;
12083{
12084 struct arm_cpu_option_table *opt;
12085 char *ext = strchr (str, '+');
12086 int optlen;
b99bd4ef 12087
03b1477f
RE
12088 if (ext != NULL)
12089 optlen = ext - str;
12090 else
12091 optlen = strlen (str);
b99bd4ef 12092
03b1477f
RE
12093 if (optlen == 0)
12094 {
12095 as_bad (_("missing cpu name `%s'"), str);
12096 return 0;
12097 }
b99bd4ef 12098
03b1477f
RE
12099 for (opt = arm_cpus; opt->name != NULL; opt++)
12100 if (strncmp (opt->name, str, optlen) == 0)
12101 {
12102 mcpu_cpu_opt = opt->value;
12103 mcpu_fpu_opt = opt->default_fpu;
b99bd4ef 12104
03b1477f
RE
12105 if (ext != NULL)
12106 return arm_parse_extension (ext, &mcpu_cpu_opt);
b99bd4ef 12107
03b1477f
RE
12108 return 1;
12109 }
b99bd4ef 12110
03b1477f
RE
12111 as_bad (_("unknown cpu `%s'"), str);
12112 return 0;
12113}
b99bd4ef 12114
03b1477f
RE
12115static int
12116arm_parse_arch (str)
12117 char *str;
12118{
12119 struct arm_arch_option_table *opt;
12120 char *ext = strchr (str, '+');
12121 int optlen;
b99bd4ef 12122
03b1477f
RE
12123 if (ext != NULL)
12124 optlen = ext - str;
12125 else
12126 optlen = strlen (str);
b99bd4ef 12127
03b1477f
RE
12128 if (optlen == 0)
12129 {
12130 as_bad (_("missing architecture name `%s'"), str);
12131 return 0;
12132 }
b99bd4ef 12133
b99bd4ef 12134
03b1477f
RE
12135 for (opt = arm_archs; opt->name != NULL; opt++)
12136 if (strcmp (opt->name, str) == 0)
12137 {
12138 march_cpu_opt = opt->value;
12139 march_fpu_opt = opt->default_fpu;
b99bd4ef 12140
03b1477f
RE
12141 if (ext != NULL)
12142 return arm_parse_extension (ext, &march_cpu_opt);
b99bd4ef 12143
03b1477f
RE
12144 return 1;
12145 }
b99bd4ef 12146
03b1477f
RE
12147 as_bad (_("unknown architecture `%s'\n"), str);
12148 return 0;
12149}
12150
12151static int
12152arm_parse_fpu (str)
12153 char *str;
12154{
12155 struct arm_fpu_option_table *opt;
b99bd4ef 12156
03b1477f
RE
12157 for (opt = arm_fpus; opt->name != NULL; opt++)
12158 if (strcmp (opt->name, str) == 0)
12159 {
12160 mfpu_opt = opt->value;
12161 return 1;
12162 }
b99bd4ef 12163
03b1477f
RE
12164 as_bad (_("unknown floating point format `%s'\n"), str);
12165 return 0;
12166}
b99bd4ef 12167
03b1477f
RE
12168struct arm_long_option_table arm_long_opts[] =
12169{
12170 {"mcpu=", N_("<cpu name>\t assemble for CPU <cpu name>"),
12171 arm_parse_cpu, NULL},
12172 {"march=", N_("<arch name>\t assemble for architecture <arch name>"),
12173 arm_parse_arch, NULL},
12174 {"mfpu=", N_("<fpu name>\t assemble for FPU architecture <fpu name>"),
12175 arm_parse_fpu, NULL},
12176 {NULL, NULL, 0, NULL}
12177};
b99bd4ef 12178
03b1477f
RE
12179int
12180md_parse_option (c, arg)
12181 int c;
12182 char * arg;
12183{
12184 struct arm_option_table *opt;
12185 struct arm_long_option_table *lopt;
b99bd4ef 12186
03b1477f
RE
12187 switch (c)
12188 {
12189#ifdef OPTION_EB
12190 case OPTION_EB:
12191 target_big_endian = 1;
b99bd4ef 12192 break;
03b1477f 12193#endif
b99bd4ef 12194
03b1477f
RE
12195#ifdef OPTION_EL
12196 case OPTION_EL:
12197 target_big_endian = 0;
b99bd4ef
NC
12198 break;
12199#endif
12200
03b1477f 12201 case 'a':
cc8a6dd0 12202 /* Listing option. Just ignore these, we don't support additional
03b1477f
RE
12203 ones. */
12204 return 0;
12205
b99bd4ef 12206 default:
03b1477f
RE
12207 for (opt = arm_opts; opt->option != NULL; opt++)
12208 {
12209 if (c == opt->option[0]
12210 && ((arg == NULL && opt->option[1] == 0)
12211 || strcmp (arg, opt->option + 1) == 0))
12212 {
12213#if WARN_DEPRECATED
12214 /* If the option is deprecated, tell the user. */
12215 if (opt->deprecated != NULL)
12216 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
12217 arg ? arg : "", _(opt->deprecated));
12218#endif
12219
12220 if (opt->var != NULL)
12221 *opt->var = opt->value;
12222
12223 return 1;
12224 }
12225 }
12226
12227 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
12228 {
cc8a6dd0 12229 /* These options are expected to have an argument. */
03b1477f
RE
12230 if (c == lopt->option[0]
12231 && arg != NULL
cc8a6dd0 12232 && strncmp (arg, lopt->option + 1,
03b1477f
RE
12233 strlen (lopt->option + 1)) == 0)
12234 {
12235#if WARN_DEPRECATED
12236 /* If the option is deprecated, tell the user. */
12237 if (lopt->deprecated != NULL)
12238 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
12239 _(lopt->deprecated));
12240#endif
12241
12242 /* Call the sup-option parser. */
12243 return (*lopt->func)(arg + strlen (lopt->option) - 1);
12244 }
12245 }
12246
12247 as_bad (_("unrecognized option `-%c%s'"), c, arg ? arg : "");
b99bd4ef
NC
12248 return 0;
12249 }
12250
12251 return 1;
12252}
12253
12254void
12255md_show_usage (fp)
12256 FILE * fp;
12257{
03b1477f
RE
12258 struct arm_option_table *opt;
12259 struct arm_long_option_table *lopt;
12260
12261 fprintf (fp, _(" ARM-specific assembler options:\n"));
12262
12263 for (opt = arm_opts; opt->option != NULL; opt++)
12264 if (opt->help != NULL)
12265 fprintf (fp, " -%-23s%s\n", opt->option, _(opt->help));
12266
12267 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
12268 if (lopt->help != NULL)
12269 fprintf (fp, " -%s%s\n", lopt->option, _(lopt->help));
12270
12271#ifdef OPTION_EB
b99bd4ef 12272 fprintf (fp, _("\
03b1477f 12273 -EB assemble code for a big-endian cpu\n"));
b99bd4ef 12274#endif
03b1477f
RE
12275
12276#ifdef OPTION_EL
b99bd4ef 12277 fprintf (fp, _("\
03b1477f 12278 -EL assemble code for a little-endian cpu\n"));
b99bd4ef
NC
12279#endif
12280}
12281
12282/* We need to be able to fix up arbitrary expressions in some statements.
12283 This is so that we can handle symbols that are an arbitrary distance from
12284 the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
12285 which returns part of an address in a form which will be valid for
12286 a data instruction. We do this by pushing the expression into a symbol
12287 in the expr_section, and creating a fix for that. */
12288
12289static void
12290fix_new_arm (frag, where, size, exp, pc_rel, reloc)
12291 fragS * frag;
12292 int where;
12293 short int size;
12294 expressionS * exp;
12295 int pc_rel;
12296 int reloc;
12297{
12298 fixS * new_fix;
12299 arm_fix_data * arm_data;
12300
12301 switch (exp->X_op)
12302 {
12303 case O_constant:
12304 case O_symbol:
12305 case O_add:
12306 case O_subtract:
12307 new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
12308 break;
12309
12310 default:
12311 new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
12312 pc_rel, reloc);
12313 break;
12314 }
12315
12316 /* Mark whether the fix is to a THUMB instruction, or an ARM
12317 instruction. */
12318 arm_data = (arm_fix_data *) obstack_alloc (& notes, sizeof (arm_fix_data));
12319 new_fix->tc_fix_data = (PTR) arm_data;
12320 arm_data->thumb_mode = thumb_mode;
12321
12322 return;
12323}
12324
12325/* This fix_new is called by cons via TC_CONS_FIX_NEW. */
12326
12327void
12328cons_fix_new_arm (frag, where, size, exp)
12329 fragS * frag;
12330 int where;
12331 int size;
12332 expressionS * exp;
12333{
12334 bfd_reloc_code_real_type type;
12335 int pcrel = 0;
12336
12337 /* Pick a reloc.
12338 FIXME: @@ Should look at CPU word size. */
12339 switch (size)
12340 {
12341 case 1:
12342 type = BFD_RELOC_8;
12343 break;
12344 case 2:
12345 type = BFD_RELOC_16;
12346 break;
12347 case 4:
12348 default:
12349 type = BFD_RELOC_32;
12350 break;
12351 case 8:
12352 type = BFD_RELOC_64;
12353 break;
12354 }
12355
12356 fix_new_exp (frag, where, (int) size, exp, pcrel, type);
12357}
12358
12359/* A good place to do this, although this was probably not intended
12360 for this kind of use. We need to dump the literal pool before
12361 references are made to a null symbol pointer. */
12362
12363void
12364arm_cleanup ()
12365{
3d0c9500 12366 literal_pool * pool;
b99bd4ef 12367
3d0c9500
NC
12368 for (pool = list_of_pools; pool; pool = pool->next)
12369 {
12370 /* Put it at the end of the relevent section. */
12371 subseg_set (pool->section, pool->sub_section);
12372 s_ltorg (0);
12373 }
b99bd4ef
NC
12374}
12375
12376void
12377arm_start_line_hook ()
12378{
12379 last_label_seen = NULL;
12380}
12381
12382void
12383arm_frob_label (sym)
12384 symbolS * sym;
12385{
12386 last_label_seen = sym;
12387
12388 ARM_SET_THUMB (sym, thumb_mode);
12389
12390#if defined OBJ_COFF || defined OBJ_ELF
12391 ARM_SET_INTERWORK (sym, support_interwork);
12392#endif
12393
12394 /* Note - do not allow local symbols (.Lxxx) to be labeled
12395 as Thumb functions. This is because these labels, whilst
12396 they exist inside Thumb code, are not the entry points for
12397 possible ARM->Thumb calls. Also, these labels can be used
12398 as part of a computed goto or switch statement. eg gcc
12399 can generate code that looks like this:
12400
12401 ldr r2, [pc, .Laaa]
12402 lsl r3, r3, #2
12403 ldr r2, [r3, r2]
12404 mov pc, r2
cc8a6dd0 12405
b99bd4ef
NC
12406 .Lbbb: .word .Lxxx
12407 .Lccc: .word .Lyyy
12408 ..etc...
12409 .Laaa: .word Lbbb
12410
12411 The first instruction loads the address of the jump table.
12412 The second instruction converts a table index into a byte offset.
12413 The third instruction gets the jump address out of the table.
12414 The fourth instruction performs the jump.
cc8a6dd0 12415
b99bd4ef
NC
12416 If the address stored at .Laaa is that of a symbol which has the
12417 Thumb_Func bit set, then the linker will arrange for this address
12418 to have the bottom bit set, which in turn would mean that the
12419 address computation performed by the third instruction would end
12420 up with the bottom bit set. Since the ARM is capable of unaligned
12421 word loads, the instruction would then load the incorrect address
12422 out of the jump table, and chaos would ensue. */
12423 if (label_is_thumb_function_name
12424 && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
12425 && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
12426 {
12427 /* When the address of a Thumb function is taken the bottom
12428 bit of that address should be set. This will allow
12429 interworking between Arm and Thumb functions to work
12430 correctly. */
12431
12432 THUMB_SET_FUNC (sym, 1);
12433
b34976b6 12434 label_is_thumb_function_name = FALSE;
b99bd4ef
NC
12435 }
12436}
12437
12438/* Adjust the symbol table. This marks Thumb symbols as distinct from
12439 ARM ones. */
12440
12441void
12442arm_adjust_symtab ()
12443{
12444#ifdef OBJ_COFF
12445 symbolS * sym;
12446
12447 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
12448 {
12449 if (ARM_IS_THUMB (sym))
12450 {
12451 if (THUMB_IS_FUNC (sym))
12452 {
12453 /* Mark the symbol as a Thumb function. */
12454 if ( S_GET_STORAGE_CLASS (sym) == C_STAT
12455 || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */
12456 S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
12457
12458 else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
12459 S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
12460 else
12461 as_bad (_("%s: unexpected function type: %d"),
12462 S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
12463 }
cc8a6dd0 12464 else switch (S_GET_STORAGE_CLASS (sym))
b99bd4ef
NC
12465 {
12466 case C_EXT:
12467 S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
12468 break;
12469 case C_STAT:
12470 S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
12471 break;
12472 case C_LABEL:
12473 S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
12474 break;
12475 default:
12476 /* Do nothing. */
12477 break;
12478 }
12479 }
12480
12481 if (ARM_IS_INTERWORK (sym))
12482 coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
12483 }
12484#endif
12485#ifdef OBJ_ELF
12486 symbolS * sym;
12487 char bind;
12488
12489 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
12490 {
12491 if (ARM_IS_THUMB (sym))
12492 {
12493 elf_symbol_type * elf_sym;
12494
12495 elf_sym = elf_symbol (symbol_get_bfdsym (sym));
12496 bind = ELF_ST_BIND (elf_sym);
12497
12498 /* If it's a .thumb_func, declare it as so,
12499 otherwise tag label as .code 16. */
12500 if (THUMB_IS_FUNC (sym))
12501 elf_sym->internal_elf_sym.st_info =
12502 ELF_ST_INFO (bind, STT_ARM_TFUNC);
12503 else
12504 elf_sym->internal_elf_sym.st_info =
12505 ELF_ST_INFO (bind, STT_ARM_16BIT);
12506 }
12507 }
12508#endif
12509}
12510
12511int
12512arm_data_in_code ()
12513{
12514 if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
12515 {
12516 *input_line_pointer = '/';
12517 input_line_pointer += 5;
12518 *input_line_pointer = 0;
12519 return 1;
12520 }
12521
12522 return 0;
12523}
12524
12525char *
12526arm_canonicalize_symbol_name (name)
12527 char * name;
12528{
12529 int len;
12530
12531 if (thumb_mode && (len = strlen (name)) > 5
12532 && streq (name + len - 5, "/data"))
12533 *(name + len - 5) = 0;
12534
12535 return name;
12536}
12537
bfc866a6 12538#if defined OBJ_COFF || defined OBJ_ELF
a161fe53 12539void
b99bd4ef
NC
12540arm_validate_fix (fixP)
12541 fixS * fixP;
12542{
12543 /* If the destination of the branch is a defined symbol which does not have
12544 the THUMB_FUNC attribute, then we must be calling a function which has
12545 the (interfacearm) attribute. We look for the Thumb entry point to that
12546 function and change the branch to refer to that function instead. */
12547 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
12548 && fixP->fx_addsy != NULL
12549 && S_IS_DEFINED (fixP->fx_addsy)
12550 && ! THUMB_IS_FUNC (fixP->fx_addsy))
12551 {
12552 fixP->fx_addsy = find_real_start (fixP->fx_addsy);
b99bd4ef 12553 }
b99bd4ef 12554}
bfc866a6 12555#endif
b99bd4ef 12556
114424c6
AM
12557int
12558arm_force_relocation (fixp)
12559 struct fix * fixp;
12560{
12561#if defined (OBJ_COFF) && defined (TE_PE)
12562 if (fixp->fx_r_type == BFD_RELOC_RVA)
12563 return 1;
12564#endif
12565#ifdef OBJ_ELF
ae6063d4 12566 if (fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
114424c6
AM
12567 || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
12568 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
12569 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
12570 return 1;
12571#endif
12572
12573 /* Resolve these relocations even if the symbol is extern or weak. */
12574 if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
47281638 12575 || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
114424c6
AM
12576 || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
12577 return 0;
12578
ae6063d4 12579 return generic_force_reloc (fixp);
114424c6
AM
12580}
12581
b99bd4ef
NC
12582#ifdef OBJ_COFF
12583/* This is a little hack to help the gas/arm/adrl.s test. It prevents
12584 local labels from being added to the output symbol table when they
12585 are used with the ADRL pseudo op. The ADRL relocation should always
12586 be resolved before the binbary is emitted, so it is safe to say that
12587 it is adjustable. */
12588
b34976b6 12589bfd_boolean
b99bd4ef
NC
12590arm_fix_adjustable (fixP)
12591 fixS * fixP;
12592{
12593 if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
12594 return 1;
12595 return 0;
12596}
12597#endif
114424c6 12598
b99bd4ef
NC
12599#ifdef OBJ_ELF
12600/* Relocations against Thumb function names must be left unadjusted,
12601 so that the linker can use this information to correctly set the
12602 bottom bit of their addresses. The MIPS version of this function
12603 also prevents relocations that are mips-16 specific, but I do not
12604 know why it does this.
12605
12606 FIXME:
12607 There is one other problem that ought to be addressed here, but
12608 which currently is not: Taking the address of a label (rather
12609 than a function) and then later jumping to that address. Such
12610 addresses also ought to have their bottom bit set (assuming that
12611 they reside in Thumb code), but at the moment they will not. */
12612
b34976b6 12613bfd_boolean
b99bd4ef
NC
12614arm_fix_adjustable (fixP)
12615 fixS * fixP;
12616{
12617 if (fixP->fx_addsy == NULL)
12618 return 1;
12619
b99bd4ef
NC
12620 if (THUMB_IS_FUNC (fixP->fx_addsy)
12621 && fixP->fx_subsy == NULL)
12622 return 0;
12623
12624 /* We need the symbol name for the VTABLE entries. */
12625 if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
12626 || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
12627 return 0;
12628
a161fe53
AM
12629 /* Don't allow symbols to be discarded on GOT related relocs. */
12630 if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
12631 || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
12632 || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF)
12633 return 0;
12634
b99bd4ef
NC
12635 return 1;
12636}
12637
12638const char *
12639elf32_arm_target_format ()
12640{
12641 if (target_big_endian)
12642 {
12643 if (target_oabi)
12644 return "elf32-bigarm-oabi";
12645 else
12646 return "elf32-bigarm";
12647 }
12648 else
12649 {
12650 if (target_oabi)
12651 return "elf32-littlearm-oabi";
12652 else
12653 return "elf32-littlearm";
12654 }
12655}
12656
12657void
12658armelf_frob_symbol (symp, puntp)
12659 symbolS * symp;
12660 int * puntp;
12661{
12662 elf_frob_symbol (symp, puntp);
12663}
12664
b99bd4ef
NC
12665static bfd_reloc_code_real_type
12666arm_parse_reloc ()
12667{
12668 char id [16];
12669 char * ip;
12670 unsigned int i;
12671 static struct
12672 {
12673 char * str;
12674 int len;
12675 bfd_reloc_code_real_type reloc;
12676 }
12677 reloc_map[] =
12678 {
12679#define MAP(str,reloc) { str, sizeof (str) - 1, reloc }
12680 MAP ("(got)", BFD_RELOC_ARM_GOT32),
12681 MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
12682 /* ScottB: Jan 30, 1998 - Added support for parsing "var(PLT)"
12683 branch instructions generated by GCC for PLT relocs. */
12684 MAP ("(plt)", BFD_RELOC_ARM_PLT32),
12685 { NULL, 0, BFD_RELOC_UNUSED }
12686#undef MAP
12687 };
12688
12689 for (i = 0, ip = input_line_pointer;
3882b010 12690 i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip));
b99bd4ef 12691 i++, ip++)
3882b010 12692 id[i] = TOLOWER (*ip);
b99bd4ef
NC
12693
12694 for (i = 0; reloc_map[i].str; i++)
12695 if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
12696 break;
12697
12698 input_line_pointer += reloc_map[i].len;
12699
12700 return reloc_map[i].reloc;
12701}
12702
12703static void
12704s_arm_elf_cons (nbytes)
12705 int nbytes;
12706{
12707 expressionS exp;
12708
12709#ifdef md_flush_pending_output
12710 md_flush_pending_output ();
12711#endif
12712
12713 if (is_it_end_of_statement ())
12714 {
12715 demand_empty_rest_of_line ();
12716 return;
12717 }
12718
12719#ifdef md_cons_align
12720 md_cons_align (nbytes);
12721#endif
12722
12723 do
12724 {
12725 bfd_reloc_code_real_type reloc;
12726
12727 expression (& exp);
12728
12729 if (exp.X_op == O_symbol
12730 && * input_line_pointer == '('
12731 && (reloc = arm_parse_reloc ()) != BFD_RELOC_UNUSED)
12732 {
12733 reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
12734 int size = bfd_get_reloc_size (howto);
12735
12736 if (size > nbytes)
12737 as_bad ("%s relocations do not fit in %d bytes",
12738 howto->name, nbytes);
12739 else
12740 {
12741 register char *p = frag_more ((int) nbytes);
12742 int offset = nbytes - size;
12743
12744 fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
12745 &exp, 0, reloc);
12746 }
12747 }
12748 else
12749 emit_expr (&exp, (unsigned int) nbytes);
12750 }
12751 while (*input_line_pointer++ == ',');
12752
12753 /* Put terminator back into stream. */
12754 input_line_pointer --;
12755 demand_empty_rest_of_line ();
12756}
12757
12758#endif /* OBJ_ELF */
12759
12760/* This is called from HANDLE_ALIGN in write.c. Fill in the contents
12761 of an rs_align_code fragment. */
12762
12763void
12764arm_handle_align (fragP)
12765 fragS *fragP;
12766{
12767 static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
12768 static char const thumb_noop[2] = { 0xc0, 0x46 };
12769 static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
12770 static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
12771
12772 int bytes, fix, noop_size;
12773 char * p;
12774 const char * noop;
cc8a6dd0 12775
b99bd4ef
NC
12776 if (fragP->fr_type != rs_align_code)
12777 return;
12778
12779 bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
12780 p = fragP->fr_literal + fragP->fr_fix;
12781 fix = 0;
cc8a6dd0 12782
b99bd4ef
NC
12783 if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
12784 bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
cc8a6dd0 12785
b99bd4ef
NC
12786 if (fragP->tc_frag_data)
12787 {
12788 if (target_big_endian)
12789 noop = thumb_bigend_noop;
12790 else
12791 noop = thumb_noop;
12792 noop_size = sizeof (thumb_noop);
12793 }
12794 else
12795 {
12796 if (target_big_endian)
12797 noop = arm_bigend_noop;
12798 else
12799 noop = arm_noop;
12800 noop_size = sizeof (arm_noop);
12801 }
cc8a6dd0 12802
b99bd4ef
NC
12803 if (bytes & (noop_size - 1))
12804 {
12805 fix = bytes & (noop_size - 1);
12806 memset (p, 0, fix);
12807 p += fix;
12808 bytes -= fix;
12809 }
12810
12811 while (bytes >= noop_size)
12812 {
12813 memcpy (p, noop, noop_size);
12814 p += noop_size;
12815 bytes -= noop_size;
12816 fix += noop_size;
12817 }
cc8a6dd0 12818
b99bd4ef
NC
12819 fragP->fr_fix += fix;
12820 fragP->fr_var = noop_size;
12821}
12822
12823/* Called from md_do_align. Used to create an alignment
12824 frag in a code section. */
12825
12826void
12827arm_frag_align_code (n, max)
12828 int n;
12829 int max;
12830{
12831 char * p;
12832
12833 /* We assume that there will never be a requirment
12834 to support alignments greater than 32 bytes. */
12835 if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
12836 as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
cc8a6dd0 12837
b99bd4ef
NC
12838 p = frag_var (rs_align_code,
12839 MAX_MEM_FOR_RS_ALIGN_CODE,
12840 1,
12841 (relax_substateT) max,
12842 (symbolS *) NULL,
12843 (offsetT) n,
12844 (char *) NULL);
12845 *p = 0;
12846
12847}
12848
12849/* Perform target specific initialisation of a frag. */
12850
12851void
12852arm_init_frag (fragP)
12853 fragS *fragP;
12854{
12855 /* Record whether this frag is in an ARM or a THUMB area. */
12856 fragP->tc_frag_data = thumb_mode;
12857}