Commit | Line | Data |
---|---|---|
338a7060 DE |
1 | /* tc-arm.c All the arm specific stuff in one convenient, huge, |
2 | slow to compile, easy to find file. | |
3 | Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) | |
4 | Modified by David Taylor (dtaylor@armltd.co.uk) | |
5 | ||
6 | Copyright (C) 1994, 1995 Free Software Foundation, Inc. | |
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 | |
22 | the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
23 | ||
24 | #include <ctype.h> | |
25 | #include <string.h> | |
26 | #define NO_RELOC 0 | |
27 | #include "as.h" | |
28 | ||
29 | /* need TARGET_CPU */ | |
30 | #include "config.h" | |
31 | #include "subsegs.h" | |
32 | #include "obstack.h" | |
33 | #include "symbols.h" | |
34 | #include "listing.h" | |
35 | ||
36 | /* ??? This is currently unused. */ | |
37 | #ifdef __STDC__ | |
38 | #define internalError() \ | |
39 | as_fatal ("ARM Internal Error, line %d, %s", __LINE__, __FILE__) | |
40 | #else | |
41 | #define internalError() as_fatal ("ARM Internal Error") | |
42 | #endif | |
43 | ||
44 | /* Types of processor to assemble for. */ | |
45 | #define ARM_1 0x00000001 | |
46 | #define ARM_2 0x00000002 | |
47 | #define ARM_250 0x00000002 /* Checkme, should this be = ARM_3? */ | |
48 | #define ARM_3 0x00000004 | |
49 | #define ARM_6 0x00000008 | |
50 | #define ARM_7 0x00000008 | |
51 | #define ARM_7DM 0x00000010 | |
52 | ||
53 | /* Some useful combinations: */ | |
54 | #define ARM_ANY 0x00ffffff | |
55 | #define ARM_2UP 0x00fffffe | |
56 | #define ARM_ALL ARM_2UP /* Not arm1 only */ | |
57 | #define ARM_3UP 0x00fffffc | |
58 | #define ARM_6UP 0x00fffff8 | |
59 | #define ARM_LONGMUL 0x00000010 /* Don't know which will have this. */ | |
60 | ||
61 | #define FPU_CORE 0x80000000 | |
62 | #define FPU_FPA10 0x40000000 | |
63 | #define FPU_FPA11 0x40000000 | |
64 | #define FPU_NONE 0 | |
65 | ||
66 | /* Some useful combinations */ | |
67 | #define FPU_ALL 0xff000000 /* Note this is ~ARM_ANY */ | |
68 | #define FPU_MEMMULTI 0x7f000000 /* Not fpu_core */ | |
69 | ||
70 | #ifndef CPU_DEFAULT | |
71 | #define CPU_DEFAULT ARM_ALL | |
72 | #endif | |
73 | ||
74 | #ifndef FPU_DEFAULT | |
75 | #define FPU_DEFAULT FPU_ALL | |
76 | #endif | |
77 | ||
78 | unsigned long cpu_variant = CPU_DEFAULT | FPU_DEFAULT; | |
79 | ||
80 | /* This array holds the chars that always start a comment. If the | |
81 | pre-processor is disabled, these aren't very useful */ | |
82 | CONST char comment_chars[] = "@"; | |
83 | ||
84 | /* This array holds the chars that only start a comment at the beginning of | |
85 | a line. If the line seems to have the form '# 123 filename' | |
86 | .line and .file directives will appear in the pre-processed output */ | |
87 | /* Note that input_file.c hand checks for '#' at the beginning of the | |
88 | first line of the input file. This is because the compiler outputs | |
89 | #NO_APP at the beginning of its output. */ | |
90 | /* Also note that comments like this one will always work. */ | |
91 | CONST char line_comment_chars[] = "#"; | |
92 | ||
93 | CONST char line_separator_chars[] = ""; | |
94 | ||
95 | /* Chars that can be used to separate mant from exp in floating point nums */ | |
96 | CONST char EXP_CHARS[] = "eE"; | |
97 | ||
98 | /* Chars that mean this number is a floating point constant */ | |
99 | /* As in 0f12.456 */ | |
100 | /* or 0d1.2345e12 */ | |
101 | ||
102 | CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP"; | |
103 | ||
104 | const int md_reloc_size = 8; /* Size of relocation record */ | |
105 | ||
106 | struct arm_it | |
107 | { | |
108 | CONST char *error; | |
109 | unsigned long instruction; | |
110 | int suffix; | |
111 | struct | |
112 | { | |
113 | bfd_reloc_code_real_type type; | |
114 | expressionS exp; | |
115 | int pc_rel; | |
116 | } reloc; | |
117 | }; | |
118 | ||
119 | struct arm_it inst; | |
120 | ||
121 | struct asm_shift | |
122 | { | |
123 | CONST char *template; | |
124 | unsigned long value; | |
125 | }; | |
126 | ||
127 | static CONST struct asm_shift shift[] = | |
128 | { | |
129 | {"asl", 0}, | |
130 | {"lsl", 0}, | |
131 | {"lsr", 0x00000020}, | |
132 | {"asr", 0x00000040}, | |
133 | {"ror", 0x00000060}, | |
134 | {"rrx", 0x00000060}, | |
135 | {"ASL", 0}, | |
136 | {"LSL", 0}, | |
137 | {"LSR", 0x00000020}, | |
138 | {"ASR", 0x00000040}, | |
139 | {"ROR", 0x00000060}, | |
140 | {"RRX", 0x00000060} | |
141 | }; | |
142 | ||
143 | #define NO_SHIFT_RESTRICT 1 | |
144 | #define SHIFT_RESTRICT 0 | |
145 | ||
146 | #define NUM_FLOAT_VALS 8 | |
147 | ||
148 | CONST char *fp_const[] = | |
149 | { | |
150 | "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0 | |
151 | }; | |
152 | ||
153 | /* Number of littlenums required to hold an extended precision number */ | |
154 | #define MAX_LITTLENUMS 6 | |
155 | ||
156 | LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS]; | |
157 | ||
158 | #define FAIL (-1) | |
159 | #define SUCCESS (0) | |
160 | ||
161 | #define SUFF_S 1 | |
162 | #define SUFF_D 2 | |
163 | #define SUFF_E 3 | |
164 | #define SUFF_P 4 | |
165 | ||
166 | #define CP_T_X 0x00008000 | |
167 | #define CP_T_Y 0x00400000 | |
168 | #define CP_T_Pre 0x01000000 | |
169 | #define CP_T_UD 0x00800000 | |
170 | #define CP_T_WB 0x00200000 | |
171 | ||
172 | #define TRANS_BIT (0x00200000) | |
173 | ||
174 | struct asm_cond | |
175 | { | |
176 | CONST char *template; | |
177 | unsigned long value; | |
178 | }; | |
179 | ||
180 | /* This is to save a hash look-up in the common case */ | |
181 | #define COND_ALWAYS 0xe0000000 | |
182 | ||
183 | static CONST struct asm_cond conds[] = | |
184 | { | |
185 | {"eq", 0x00000000}, | |
186 | {"ne", 0x10000000}, | |
187 | {"cs", 0x20000000}, {"hs", 0x20000000}, | |
188 | {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000}, | |
189 | {"mi", 0x40000000}, | |
190 | {"pl", 0x50000000}, | |
191 | {"vs", 0x60000000}, | |
192 | {"vc", 0x70000000}, | |
193 | {"hi", 0x80000000}, | |
194 | {"ls", 0x90000000}, | |
195 | {"ge", 0xa0000000}, | |
196 | {"lt", 0xb0000000}, | |
197 | {"gt", 0xc0000000}, | |
198 | {"le", 0xd0000000}, | |
199 | {"al", 0xe0000000}, | |
200 | {"nv", 0xf0000000} | |
201 | }; | |
202 | ||
203 | ||
204 | struct asm_flg | |
205 | { | |
206 | CONST char *template; /* Basic flag string */ | |
207 | unsigned long set_bits; /* Bits to set */ | |
208 | }; | |
209 | ||
210 | static CONST struct asm_flg s_flag[] = | |
211 | { | |
212 | {"s", 0x00100000}, | |
213 | {NULL, 0} | |
214 | }; | |
215 | ||
216 | static CONST struct asm_flg ldst_flags[] = | |
217 | { | |
218 | {"b", 0x00400000}, | |
219 | {"t", TRANS_BIT}, | |
220 | {"bt", 0x00400000 | TRANS_BIT}, | |
221 | {NULL, 0} | |
222 | }; | |
223 | ||
224 | static CONST struct asm_flg byte_flag[] = | |
225 | { | |
226 | {"b", 0x00400000}, | |
227 | {NULL, 0} | |
228 | }; | |
229 | ||
230 | static CONST struct asm_flg cmp_flags[] = | |
231 | { | |
232 | {"s", 0x00100000}, | |
233 | {"p", 0x0010f000}, | |
234 | {NULL, 0} | |
235 | }; | |
236 | ||
237 | static CONST struct asm_flg ldm_flags[] = | |
238 | { | |
239 | {"ed", 0x01800000}, | |
240 | {"fd", 0x00800000}, | |
241 | {"ea", 0x01000000}, | |
242 | {"fa", 0x08000000}, | |
243 | {"ib", 0x01800000}, | |
244 | {"ia", 0x00800000}, | |
245 | {"db", 0x01000000}, | |
246 | {"da", 0x08000000}, | |
247 | {NULL, 0} | |
248 | }; | |
249 | ||
250 | static CONST struct asm_flg stm_flags[] = | |
251 | { | |
252 | {"ed", 0x08000000}, | |
253 | {"fd", 0x01000000}, | |
254 | {"ea", 0x00800000}, | |
255 | {"fa", 0x01800000}, | |
256 | {"ib", 0x01800000}, | |
257 | {"ia", 0x00800000}, | |
258 | {"db", 0x01000000}, | |
259 | {"da", 0x08000000}, | |
260 | {NULL, 0} | |
261 | }; | |
262 | ||
263 | static CONST struct asm_flg lfm_flags[] = | |
264 | { | |
265 | {"fd", 0x00800000}, | |
266 | {"ea", 0x01000000}, | |
267 | {NULL, 0} | |
268 | }; | |
269 | ||
270 | static CONST struct asm_flg sfm_flags[] = | |
271 | { | |
272 | {"fd", 0x01000000}, | |
273 | {"ea", 0x00800000}, | |
274 | {NULL, 0} | |
275 | }; | |
276 | ||
277 | static CONST struct asm_flg round_flags[] = | |
278 | { | |
279 | {"p", 0x00000020}, | |
280 | {"m", 0x00000040}, | |
281 | {"z", 0x00000060}, | |
282 | {NULL, 0} | |
283 | }; | |
284 | ||
285 | static CONST struct asm_flg except_flag[] = | |
286 | { | |
287 | {"e", 0x00400000}, | |
288 | {NULL, 0} | |
289 | }; | |
290 | ||
291 | static CONST struct asm_flg cplong_flag[] = | |
292 | { | |
293 | {"l", 0x00400000}, | |
294 | {NULL, 0} | |
295 | }; | |
296 | ||
297 | struct asm_psr | |
298 | { | |
299 | CONST char *template; | |
300 | unsigned long number; | |
301 | }; | |
302 | ||
303 | #define PSR_ALL 0x00010000 | |
304 | ||
305 | static CONST struct asm_psr psrs[] = | |
306 | { | |
307 | /* Valid <psr>'s */ | |
308 | {"cpsr", 0}, | |
309 | {"cpsr_all", 0}, | |
310 | {"spsr", 1}, | |
311 | {"spsr_all", 1}, | |
312 | ||
313 | /* Valid <psrf>'s */ | |
314 | {"cpsr_flg", 2}, | |
315 | {"spsr_flg", 3} | |
316 | }; | |
317 | ||
318 | /* Functions called by parser */ | |
319 | /* ARM instructions */ | |
320 | static void do_arit PARAMS ((char *operands, unsigned long flags)); | |
321 | static void do_cmp PARAMS ((char *operands, unsigned long flags)); | |
322 | static void do_mov PARAMS ((char *operands, unsigned long flags)); | |
323 | static void do_ldst PARAMS ((char *operands, unsigned long flags)); | |
324 | static void do_ldmstm PARAMS ((char *operands, unsigned long flags)); | |
325 | static void do_branch PARAMS ((char *operands, unsigned long flags)); | |
326 | static void do_swi PARAMS ((char *operands, unsigned long flags)); | |
327 | /* Pseudo Op codes */ | |
328 | static void do_adr PARAMS ((char *operands, unsigned long flags)); | |
329 | static void do_nop PARAMS ((char *operands, unsigned long flags)); | |
330 | /* ARM 2 */ | |
331 | static void do_mul PARAMS ((char *operands, unsigned long flags)); | |
332 | static void do_mla PARAMS ((char *operands, unsigned long flags)); | |
333 | /* ARM 3 */ | |
334 | static void do_swap PARAMS ((char *operands, unsigned long flags)); | |
335 | /* ARM 6 */ | |
336 | static void do_msr PARAMS ((char *operands, unsigned long flags)); | |
337 | static void do_mrs PARAMS ((char *operands, unsigned long flags)); | |
338 | /* ARM 7DM */ | |
339 | static void do_mull PARAMS ((char *operands, unsigned long flags)); | |
340 | /* Coprocessor Instructions */ | |
341 | static void do_cdp PARAMS ((char *operands, unsigned long flags)); | |
342 | static void do_lstc PARAMS ((char *operands, unsigned long flags)); | |
343 | static void do_co_reg PARAMS ((char *operands, unsigned long flags)); | |
344 | static void do_fp_ctrl PARAMS ((char *operands, unsigned long flags)); | |
345 | static void do_fp_ldst PARAMS ((char *operands, unsigned long flags)); | |
346 | static void do_fp_ldmstm PARAMS ((char *operands, unsigned long flags)); | |
347 | static void do_fp_dyadic PARAMS ((char *operands, unsigned long flags)); | |
348 | static void do_fp_monadic PARAMS ((char *operands, unsigned long flags)); | |
349 | static void do_fp_cmp PARAMS ((char *operands, unsigned long flags)); | |
350 | static void do_fp_from_reg PARAMS ((char *operands, unsigned long flags)); | |
351 | static void do_fp_to_reg PARAMS ((char *operands, unsigned long flags)); | |
352 | ||
353 | static void fix_new_arm PARAMS ((fragS *frag, int where, | |
354 | short int size, expressionS *exp, | |
355 | int pc_rel, int reloc)); | |
356 | static int arm_reg_parse PARAMS ((char **ccp)); | |
357 | static int arm_psr_parse PARAMS ((char **ccp)); | |
358 | ||
359 | /* All instructions take 4 bytes in the object file */ | |
360 | ||
361 | #define INSN_SIZE 4 | |
362 | ||
363 | /* LONGEST_INST is the longest basic instruction name without conditions or | |
364 | * flags. | |
365 | * ARM7DM has 4 of length 5 | |
366 | */ | |
367 | ||
368 | #define LONGEST_INST 5 | |
369 | ||
370 | struct asm_opcode | |
371 | { | |
372 | CONST char *template; /* Basic string to match */ | |
373 | unsigned long value; /* Basic instruction code */ | |
374 | CONST char *comp_suffix; /* Compulsory suffix that must follow conds */ | |
375 | CONST struct asm_flg *flags; /* Bits to toggle if flag 'n' set */ | |
376 | unsigned long variants; /* Which CPU variants this exists for */ | |
377 | void (*parms)(); /* Function to call to parse args */ | |
378 | }; | |
379 | ||
380 | static CONST struct asm_opcode insns[] = | |
381 | { | |
382 | /* ARM Instructions */ | |
383 | {"and", 0x00000000, NULL, s_flag, ARM_ANY, do_arit}, | |
384 | {"eor", 0x00200000, NULL, s_flag, ARM_ANY, do_arit}, | |
385 | {"sub", 0x00400000, NULL, s_flag, ARM_ANY, do_arit}, | |
386 | {"rsb", 0x00600000, NULL, s_flag, ARM_ANY, do_arit}, | |
387 | {"add", 0x00800000, NULL, s_flag, ARM_ANY, do_arit}, | |
388 | {"adc", 0x00a00000, NULL, s_flag, ARM_ANY, do_arit}, | |
389 | {"sbc", 0x00c00000, NULL, s_flag, ARM_ANY, do_arit}, | |
390 | {"rsc", 0x00e00000, NULL, s_flag, ARM_ANY, do_arit}, | |
391 | {"orr", 0x01800000, NULL, s_flag, ARM_ANY, do_arit}, | |
392 | {"bic", 0x01c00000, NULL, s_flag, ARM_ANY, do_arit}, | |
393 | {"tst", 0x01000000, NULL, cmp_flags, ARM_ANY, do_cmp}, | |
394 | {"teq", 0x01200000, NULL, cmp_flags, ARM_ANY, do_cmp}, | |
395 | {"cmp", 0x01400000, NULL, cmp_flags, ARM_ANY, do_cmp}, | |
396 | {"cmn", 0x01600000, NULL, cmp_flags, ARM_ANY, do_cmp}, | |
397 | {"mov", 0x01a00000, NULL, s_flag, ARM_ANY, do_mov}, | |
398 | {"mvn", 0x01e00000, NULL, s_flag, ARM_ANY, do_mov}, | |
399 | {"str", 0x04000000, NULL, ldst_flags, ARM_ANY, do_ldst}, | |
400 | {"ldr", 0x04100000, NULL, ldst_flags, ARM_ANY, do_ldst}, | |
401 | {"stm", 0x08000000, NULL, stm_flags, ARM_ANY, do_ldmstm}, | |
402 | {"ldm", 0x08100000, NULL, ldm_flags, ARM_ANY, do_ldmstm}, | |
403 | {"swi", 0x0f000000, NULL, NULL, ARM_ANY, do_swi}, | |
404 | {"bl", 0x0b000000, NULL, NULL, ARM_ANY, do_branch}, | |
405 | {"b", 0x0a000000, NULL, NULL, ARM_ANY, do_branch}, | |
406 | ||
407 | /* Pseudo ops */ | |
408 | {"adr", 0x028f0000, NULL, NULL, ARM_ANY, do_adr}, | |
409 | {"nop", 0x01a00000, NULL, NULL, ARM_ANY, do_nop}, | |
410 | ||
411 | /* ARM 2 multiplies */ | |
412 | {"mul", 0x00000090, NULL, s_flag, ARM_2UP, do_mul}, | |
413 | {"mla", 0x00200090, NULL, s_flag, ARM_2UP, do_mla}, | |
414 | ||
415 | /* ARM 3 - swp instructions */ | |
416 | {"swp", 0x01000090, NULL, byte_flag, ARM_3UP, do_swap}, | |
417 | ||
418 | /* ARM 6 Coprocessor instructions */ | |
419 | {"mrs", 0x010f0000, NULL, NULL, ARM_6UP, do_mrs}, | |
420 | {"msr", 0x0128f000, NULL, NULL, ARM_6UP, do_msr}, | |
421 | ||
422 | /* ARM 7DM long multiplies - need signed/unsigned flags! */ | |
423 | {"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull}, | |
424 | {"umull", 0x00800090, NULL, s_flag, ARM_LONGMUL, do_mull}, | |
425 | {"smlal", 0x00e00090, NULL, s_flag, ARM_LONGMUL, do_mull}, | |
426 | {"umlal", 0x00a00090, NULL, s_flag, ARM_LONGMUL, do_mull}, | |
427 | ||
428 | /* Floating point instructions */ | |
429 | {"wfs", 0x0e200110, NULL, NULL, FPU_ALL, do_fp_ctrl}, | |
430 | {"rfs", 0x0e300110, NULL, NULL, FPU_ALL, do_fp_ctrl}, | |
431 | {"wfc", 0x0e400110, NULL, NULL, FPU_ALL, do_fp_ctrl}, | |
432 | {"rfc", 0x0e500110, NULL, NULL, FPU_ALL, do_fp_ctrl}, | |
433 | {"ldf", 0x0c100100, "sdep", NULL, FPU_ALL, do_fp_ldst}, | |
434 | {"stf", 0x0c000100, "sdep", NULL, FPU_ALL, do_fp_ldst}, | |
435 | {"lfm", 0x0c100200, NULL, lfm_flags, FPU_MEMMULTI, do_fp_ldmstm}, | |
436 | {"sfm", 0x0c000200, NULL, sfm_flags, FPU_MEMMULTI, do_fp_ldmstm}, | |
437 | {"mvf", 0x0e008100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
438 | {"mnf", 0x0e108100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
439 | {"abs", 0x0e208100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
440 | {"rnd", 0x0e308100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
441 | {"sqt", 0x0e408100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
442 | {"log", 0x0e508100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
443 | {"lgn", 0x0e608100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
444 | {"exp", 0x0e708100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
445 | {"sin", 0x0e808100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
446 | {"cos", 0x0e908100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
447 | {"tan", 0x0ea08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
448 | {"asn", 0x0eb08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
449 | {"acs", 0x0ec08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
450 | {"atn", 0x0ed08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
451 | {"urd", 0x0ee08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
452 | {"nrm", 0x0ef08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, | |
453 | {"adf", 0x0e000100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
454 | {"suf", 0x0e200100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
455 | {"rsf", 0x0e300100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
456 | {"muf", 0x0e100100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
457 | {"dvf", 0x0e400100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
458 | {"rdf", 0x0e500100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
459 | {"pow", 0x0e600100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
460 | {"rpw", 0x0e700100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
461 | {"rmf", 0x0e800100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
462 | {"fml", 0x0e900100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
463 | {"fdv", 0x0ea00100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
464 | {"frd", 0x0eb00100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
465 | {"pol", 0x0ec00100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, | |
466 | {"cmf", 0x0e90f110, NULL, except_flag, FPU_ALL, do_fp_cmp}, | |
467 | {"cnf", 0x0eb0f110, NULL, except_flag, FPU_ALL, do_fp_cmp}, | |
468 | /* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should not | |
469 | be an optional suffix, but part of the instruction. To be compatible, | |
470 | we accept either. */ | |
471 | {"cmfe", 0x0ed0f110, NULL, NULL, FPU_ALL, do_fp_cmp}, | |
472 | {"cnfe", 0x0ef0f110, NULL, NULL, FPU_ALL, do_fp_cmp}, | |
473 | {"flt", 0x0e000110, "sde", round_flags, FPU_ALL, do_fp_from_reg}, | |
474 | {"fix", 0x0e100110, NULL, round_flags, FPU_ALL, do_fp_to_reg}, | |
475 | ||
476 | /* Generic copressor instructions */ | |
477 | {"cdp", 0x0e000000, NULL, NULL, ARM_ANY, do_cdp}, | |
478 | {"ldc", 0x0c100000, NULL, cplong_flag, ARM_ANY, do_lstc}, | |
479 | {"stc", 0x0c000000, NULL, cplong_flag, ARM_ANY, do_lstc}, | |
480 | {"mcr", 0x0e000010, NULL, NULL, ARM_ANY, do_co_reg}, | |
481 | {"mrc", 0x0e100010, NULL, NULL, ARM_ANY, do_co_reg}, | |
482 | }; | |
483 | ||
484 | /* defines for various bits that we will want to toggle */ | |
485 | ||
486 | #define INST_IMMEDIATE 0x02000000 | |
487 | #define OFFSET_REG 0x02000000 | |
488 | #define SHIFT_BY_REG 0x00000010 | |
489 | #define PRE_INDEX 0x01000000 | |
490 | #define INDEX_UP 0x00800000 | |
491 | #define WRITE_BACK 0x00200000 | |
492 | #define MULTI_SET_PSR 0x00400000 | |
493 | ||
494 | #define LITERAL_MASK 0xf000f000 | |
495 | #define COND_MASK 0xf0000000 | |
496 | #define OPCODE_MASK 0xfe1fffff | |
497 | #define DATA_OP_SHIFT 21 | |
498 | ||
499 | /* Codes to distinguish the arithmetic instructions */ | |
500 | ||
501 | #define OPCODE_AND 0 | |
502 | #define OPCODE_EOR 1 | |
503 | #define OPCODE_SUB 2 | |
504 | #define OPCODE_RSB 3 | |
505 | #define OPCODE_ADD 4 | |
506 | #define OPCODE_ADC 5 | |
507 | #define OPCODE_SBC 6 | |
508 | #define OPCODE_RSC 7 | |
509 | #define OPCODE_TST 8 | |
510 | #define OPCODE_TEQ 9 | |
511 | #define OPCODE_CMP 10 | |
512 | #define OPCODE_CMN 11 | |
513 | #define OPCODE_ORR 12 | |
514 | #define OPCODE_MOV 13 | |
515 | #define OPCODE_BIC 14 | |
516 | #define OPCODE_MVN 15 | |
517 | ||
518 | struct reg_entry | |
519 | { | |
520 | CONST char *name; | |
521 | int number; | |
522 | }; | |
523 | ||
524 | #define int_register(reg) ((reg) >= 0 && (reg) <= 15) | |
525 | #define cp_register(reg) ((reg) >= 32 && (reg) <= 47) | |
526 | #define fp_register(reg) ((reg) >= 16 && (reg) <= 23) | |
527 | ||
528 | #define REG_PC 15 | |
529 | ||
530 | /* These are the standard names; Users can add aliases with .req */ | |
531 | static CONST struct reg_entry reg_table[] = | |
532 | { | |
533 | /* Processor Register Numbers */ | |
534 | {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3}, | |
535 | {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7}, | |
536 | {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11}, | |
537 | {"r12", 12}, {"r13", 13}, {"r14", 14}, {"r15", REG_PC}, | |
538 | /* APCS conventions */ | |
539 | {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3}, | |
540 | {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, {"v5", 8}, | |
541 | {"v6", 9}, {"sb", 9}, {"v7", 10}, {"sl", 10}, | |
542 | {"fp", 11}, {"ip", 12}, {"sp", 13}, {"lr", 14}, {"pc", REG_PC}, | |
543 | /* FP Registers */ | |
544 | {"f0", 16}, {"f1", 17}, {"f2", 18}, {"f3", 19}, | |
545 | {"f4", 20}, {"f5", 21}, {"f6", 22}, {"f7", 23}, | |
546 | {"c0", 32}, {"c1", 33}, {"c2", 34}, {"c3", 35}, | |
547 | {"c4", 36}, {"c5", 37}, {"c6", 38}, {"c7", 39}, | |
548 | {"c8", 40}, {"c9", 41}, {"c10", 42}, {"c11", 43}, | |
549 | {"c12", 44}, {"c13", 45}, {"c14", 46}, {"c15", 47}, | |
550 | {"cr0", 32}, {"cr1", 33}, {"cr2", 34}, {"cr3", 35}, | |
551 | {"cr4", 36}, {"cr5", 37}, {"cr6", 38}, {"cr7", 39}, | |
552 | {"cr8", 40}, {"cr9", 41}, {"cr10", 42}, {"cr11", 43}, | |
553 | {"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47}, | |
554 | {NULL, 0} | |
555 | }; | |
556 | ||
557 | static CONST char *bad_args = "Bad arguments to instruction"; | |
558 | static CONST char *bad_pc = "r15 not allowed here"; | |
559 | ||
560 | static struct hash_control *arm_ops_hsh = NULL; | |
561 | static struct hash_control *arm_cond_hsh = NULL; | |
562 | static struct hash_control *arm_shift_hsh = NULL; | |
563 | static struct hash_control *arm_reg_hsh = NULL; | |
564 | static struct hash_control *arm_psr_hsh = NULL; | |
565 | ||
566 | /* This table describes all the machine specific pseudo-ops the assembler | |
567 | has to support. The fields are: | |
568 | pseudo-op name without dot | |
569 | function to call to execute this pseudo-op | |
570 | Integer arg to pass to the function | |
571 | */ | |
572 | ||
573 | static void s_req PARAMS ((int)); | |
574 | static void s_align PARAMS ((int)); | |
575 | static void s_bss PARAMS ((int)); | |
576 | static void s_even PARAMS ((int)); | |
577 | static void s_ltorg PARAMS ((int)); | |
578 | ||
579 | static int my_get_expression PARAMS ((expressionS *, char **)); | |
580 | ||
581 | CONST pseudo_typeS md_pseudo_table[] = | |
582 | { | |
583 | {"req", s_req, 0}, /* Never called becasue '.req' does not start line */ | |
584 | {"bss", s_bss, 0}, | |
585 | {"align", s_align, 0}, | |
586 | {"even", s_even, 0}, | |
587 | {"ltorg", s_ltorg, 0}, | |
588 | {"pool", s_ltorg, 0}, | |
589 | {"word", cons, 4}, | |
590 | {"extend", float_cons, 'x'}, | |
591 | {"ldouble", float_cons, 'x'}, | |
592 | {"packed", float_cons, 'p'}, | |
593 | {0, 0, 0} | |
594 | }; | |
595 | ||
596 | /* Stuff needed to resolve the label ambiguity | |
597 | As: | |
598 | ... | |
599 | label: <insn> | |
600 | may differ from: | |
601 | ... | |
602 | label: | |
603 | <insn> | |
604 | */ | |
605 | ||
606 | symbolS *last_label_seen; | |
607 | ||
608 | /* Literal stuff */ | |
609 | ||
610 | #define MAX_LITERAL_POOL_SIZE 1024 | |
611 | ||
612 | typedef struct literalS | |
613 | { | |
614 | struct expressionS exp; | |
615 | struct arm_it *inst; | |
616 | } literalT; | |
617 | ||
618 | literalT literals[MAX_LITERAL_POOL_SIZE]; | |
619 | int next_literal_pool_place = 0; /* Next free entry in the pool */ | |
620 | int lit_pool_num = 1; /* Next literal pool number */ | |
621 | symbolS *current_poolP = NULL; | |
622 | symbolS *symbol_make_empty (); | |
623 | ||
624 | static int | |
625 | add_to_lit_pool () | |
626 | { | |
627 | if (current_poolP == NULL) | |
628 | current_poolP = symbol_make_empty(); | |
629 | ||
630 | if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE) | |
631 | { | |
632 | inst.error = "Literal Pool Overflow\n"; | |
633 | return FAIL; | |
634 | } | |
635 | ||
636 | literals[next_literal_pool_place].exp = inst.reloc.exp; | |
637 | inst.reloc.exp.X_op = O_symbol; | |
638 | inst.reloc.exp.X_add_number = (next_literal_pool_place++)*4-8; | |
639 | inst.reloc.exp.X_add_symbol = current_poolP; | |
640 | ||
641 | return SUCCESS; | |
642 | } | |
643 | ||
644 | /* Can't use symbol_new here, so have to create a symbol and them at | |
645 | a later datete assign iot a value. Thats what these functions do */ | |
646 | static void | |
647 | symbol_locate (symbolP, name, segment, valu, frag) | |
648 | symbolS *symbolP; | |
649 | CONST char *name; /* It is copied, the caller can modify */ | |
650 | segT segment; /* Segment identifier (SEG_<something>) */ | |
651 | valueT valu; /* Symbol value */ | |
652 | fragS *frag; /* Associated fragment */ | |
653 | { | |
654 | unsigned int name_length; | |
655 | char *preserved_copy_of_name; | |
656 | ||
657 | name_length = strlen (name) + 1; /* +1 for \0 */ | |
658 | obstack_grow (¬es, name, name_length); | |
659 | preserved_copy_of_name = obstack_finish (¬es); | |
660 | #ifdef STRIP_UNDERSCORE | |
661 | if (preserved_copy_of_name[0] == '_') | |
662 | preserved_copy_of_name++; | |
663 | #endif | |
664 | ||
665 | #ifdef tc_canonicalize_symbol_name | |
666 | preserved_copy_of_name = | |
667 | tc_canonicalize_symbol_name (preserved_copy_of_name); | |
668 | #endif | |
669 | ||
670 | S_SET_NAME (symbolP, preserved_copy_of_name); | |
671 | ||
672 | S_SET_SEGMENT (symbolP, segment); | |
673 | S_SET_VALUE (symbolP, valu); | |
674 | symbol_clear_list_pointers(symbolP); | |
675 | ||
676 | symbolP->sy_frag = frag; | |
677 | ||
678 | /* | |
679 | * Link to end of symbol chain. | |
680 | */ | |
681 | { | |
682 | extern int symbol_table_frozen; | |
683 | if (symbol_table_frozen) | |
684 | abort (); | |
685 | } | |
686 | ||
687 | symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP); | |
688 | ||
689 | obj_symbol_new_hook (symbolP); | |
690 | ||
691 | #ifdef tc_symbol_new_hook | |
692 | tc_symbol_new_hook (symbolP); | |
693 | #endif | |
694 | ||
695 | #ifdef DEBUG_SYMS | |
696 | verify_symbol_chain(symbol_rootP, symbol_lastP); | |
697 | #endif /* DEBUG_SYMS */ | |
698 | } | |
699 | ||
700 | symbolS * | |
701 | symbol_make_empty () | |
702 | { | |
703 | symbolS *symbolP; | |
704 | ||
705 | symbolP = (symbolS *) obstack_alloc (¬es, sizeof (symbolS)); | |
706 | ||
707 | /* symbol must be born in some fixed state. This seems as good as any. */ | |
708 | memset (symbolP, 0, sizeof (symbolS)); | |
709 | ||
710 | #ifdef BFD_ASSEMBLER | |
711 | symbolP->bsym = bfd_make_empty_symbol (stdoutput); | |
712 | assert (symbolP->bsym != 0); | |
713 | symbolP->bsym->udata.p = (PTR) symbolP; | |
714 | #endif | |
715 | ||
716 | return symbolP; | |
717 | } | |
718 | ||
719 | /* Check that an immediate is valid, and if so, convert it to the right format | |
720 | */ | |
721 | ||
722 | /* OH, for a rotate instruction in C! */ | |
723 | ||
724 | static int | |
725 | validate_immediate (val) | |
726 | int val; | |
727 | { | |
728 | unsigned int a = (unsigned int) val; | |
729 | int i; | |
730 | ||
731 | /* Do the easy (and most common ones) quickly */ | |
732 | for (i = 0; i <= 24; i += 2) | |
733 | { | |
734 | if ((a & (0xff << i)) == a) | |
735 | return (int) (((32 - i) & 0x1e) << 7) | ((a >> i) & 0xff); | |
736 | } | |
737 | ||
738 | /* Now do the harder ones */ | |
739 | for (; i < 32; i += 2) | |
740 | { | |
741 | if ((a & ((0xff << i) | (0xff >> (32 - i)))) == a) | |
742 | { | |
743 | a = ((a >> i) & 0xff) | ((a << (32 - i)) & 0xff); | |
744 | return (int) a | (((32 - i) >> 1) << 8); | |
745 | } | |
746 | } | |
747 | return FAIL; | |
748 | } | |
749 | ||
750 | static int | |
751 | validate_offset_imm (val) | |
752 | int val; | |
753 | { | |
754 | if (val < -4095 || val > 4095) | |
755 | as_bad ("bad immediate value for offset (%d)", val); | |
756 | return val; | |
757 | } | |
758 | ||
759 | ||
760 | static void | |
761 | s_req (a) | |
762 | int a; | |
763 | { | |
764 | as_bad ("Invalid syntax for .req directive."); | |
765 | } | |
766 | ||
767 | static void | |
768 | s_bss (ignore) | |
769 | int ignore; | |
770 | { | |
771 | /* We don't support putting frags in the BSS segment, we fake it by | |
772 | marking in_bss, then looking at s_skip for clues?.. */ | |
773 | subseg_set (bss_section, 0); | |
774 | demand_empty_rest_of_line (); | |
775 | } | |
776 | ||
777 | static void | |
778 | s_even (ignore) | |
779 | int ignore; | |
780 | { | |
781 | if (!need_pass_2) /* Never make frag if expect extra pass. */ | |
782 | frag_align (1, 0); | |
783 | record_alignment (now_seg, 1); | |
784 | demand_empty_rest_of_line (); | |
785 | } | |
786 | ||
787 | static void | |
788 | s_ltorg (internal) | |
789 | int internal; | |
790 | { | |
791 | int lit_count = 0; | |
792 | char sym_name[20]; | |
793 | ||
794 | if (current_poolP == NULL) | |
795 | { | |
796 | /* Nothing to do */ | |
797 | if (!internal) | |
798 | as_tsktsk ("Nothing to put in the pool\n"); | |
799 | return; | |
800 | } | |
801 | ||
802 | /* Align pool as you have word accesses */ | |
803 | /* Only make a frag if we have to ... */ | |
804 | if (!need_pass_2) | |
805 | frag_align (2, 0); | |
806 | ||
807 | record_alignment (now_seg, 2); | |
808 | ||
809 | if (internal) | |
810 | as_tsktsk ("Inserting implicit pool at change of section"); | |
811 | ||
812 | sprintf (sym_name, "$$lit_\002%x", lit_pool_num++); | |
813 | ||
814 | symbol_locate (current_poolP, sym_name, now_seg, | |
815 | (valueT) ((char *)obstack_next_free (&frags) | |
816 | - frag_now->fr_literal), frag_now); | |
817 | symbol_table_insert (current_poolP); | |
818 | ||
819 | while (lit_count < next_literal_pool_place) | |
820 | /* First output the expression in the instruction to the pool */ | |
821 | emit_expr (&(literals[lit_count++].exp), 4); /* .word */ | |
822 | ||
823 | next_literal_pool_place = 0; | |
824 | current_poolP = NULL; | |
825 | } | |
826 | ||
827 | static void | |
828 | arm_align (power, fill) | |
829 | int power; | |
830 | int fill; | |
831 | { | |
832 | /* Only make a frag if we HAVE to ... */ | |
833 | if (power && !need_pass_2) | |
834 | frag_align (power, fill); | |
835 | ||
836 | record_alignment (now_seg, power); | |
837 | } | |
838 | ||
839 | static void | |
840 | s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */ | |
841 | int unused; | |
842 | { | |
843 | register int temp; | |
844 | register long temp_fill; | |
845 | long max_alignment = 15; | |
846 | ||
847 | temp = get_absolute_expression (); | |
848 | if (temp > max_alignment) | |
849 | as_bad ("Alignment too large: %d. assumed.", temp = max_alignment); | |
850 | else if (temp < 0) | |
851 | { | |
852 | as_bad ("Alignment negative. 0 assumed."); | |
853 | temp = 0; | |
854 | } | |
855 | ||
856 | if (*input_line_pointer == ',') | |
857 | { | |
858 | input_line_pointer++; | |
859 | temp_fill = get_absolute_expression (); | |
860 | } | |
861 | else | |
862 | temp_fill = 0; | |
863 | ||
864 | if (!temp) | |
865 | temp = 2; | |
866 | ||
867 | /* Only make a frag if we HAVE to. . . */ | |
868 | if (temp && !need_pass_2) | |
869 | frag_align (temp, (int) temp_fill); | |
870 | demand_empty_rest_of_line (); | |
871 | ||
872 | record_alignment (now_seg, temp); | |
873 | } | |
874 | ||
875 | static void | |
876 | end_of_line (str) | |
877 | char *str; | |
878 | { | |
879 | while (*str == ' ') | |
880 | str++; | |
881 | ||
882 | if (*str != '\0') | |
883 | inst.error = "Garbage following instruction"; | |
884 | } | |
885 | ||
886 | static int | |
887 | skip_past_comma (str) | |
888 | char **str; | |
889 | { | |
890 | char *p = *str, c; | |
891 | int comma = 0; | |
892 | ||
893 | while ((c = *p) == ' ' || c == ',') | |
894 | { | |
895 | p++; | |
896 | if (c == ',' && comma++) | |
897 | return FAIL; | |
898 | } | |
899 | ||
900 | if (c == '\0') | |
901 | return FAIL; | |
902 | ||
903 | *str = p; | |
904 | return comma ? SUCCESS : FAIL; | |
905 | } | |
906 | ||
907 | /* A standard register must be given at this point. Shift is the place to | |
908 | put it in the instruction. */ | |
909 | ||
910 | static int | |
911 | reg_required_here (str, shift) | |
912 | char **str; | |
913 | int shift; | |
914 | { | |
915 | int reg; | |
916 | char *start = *str; | |
917 | ||
918 | if ((reg = arm_reg_parse (str)) != FAIL && int_register (reg)) | |
919 | { | |
920 | inst.instruction |= reg << shift; | |
921 | return reg; | |
922 | } | |
923 | ||
924 | /* In the few cases where we might be able to accept something else | |
925 | this error can be overridden */ | |
926 | inst.error = "Register expected"; | |
927 | ||
928 | /* Restore the start point, we may have got a reg of the wrong class. */ | |
929 | *str = start; | |
930 | return FAIL; | |
931 | } | |
932 | ||
933 | static int | |
934 | psr_required_here (str, shift) | |
935 | char **str; | |
936 | int shift; | |
937 | { | |
938 | int psr; | |
939 | char *start = *str; | |
940 | ||
941 | if ((psr = arm_psr_parse (str)) != FAIL && psr < 2) | |
942 | { | |
943 | if (psr == 1) | |
944 | inst.instruction |= 1 << shift; /* Should be bit 22 */ | |
945 | return psr; | |
946 | } | |
947 | ||
948 | /* In the few cases where we might be able to accept something else | |
949 | this error can be overridden */ | |
950 | inst.error = "<psr> expected"; | |
951 | ||
952 | /* Restore the start point. */ | |
953 | *str = start; | |
954 | return FAIL; | |
955 | } | |
956 | ||
957 | static int | |
958 | psrf_required_here (str, shift) | |
959 | char **str; | |
960 | int shift; | |
961 | { | |
962 | int psrf; | |
963 | char *start = *str; | |
964 | ||
965 | if ((psrf = arm_psr_parse (str)) != FAIL && psrf > 1) | |
966 | { | |
967 | if (psrf == 1 || psrf == 3) | |
968 | inst.instruction |= 1 << shift; /* Should be bit 22 */ | |
969 | return psrf; | |
970 | } | |
971 | ||
972 | /* In the few cases where we might be able to accept something else | |
973 | this error can be overridden */ | |
974 | inst.error = "<psrf> expected"; | |
975 | ||
976 | /* Restore the start point. */ | |
977 | *str = start; | |
978 | return FAIL; | |
979 | } | |
980 | ||
981 | static int | |
982 | co_proc_number (str) | |
983 | char **str; | |
984 | { | |
985 | int processor, pchar; | |
986 | ||
987 | while (**str == ' ') | |
988 | (*str)++; | |
989 | ||
990 | /* The data sheet seems to imply that just a number on its own is valid | |
991 | here, but the RISC iX assembler seems to accept a prefix 'p'. We will | |
992 | accept either. */ | |
993 | if (**str == 'p' || **str == 'P') | |
994 | (*str)++; | |
995 | ||
996 | pchar = *(*str)++; | |
997 | if (pchar >= '0' && pchar <= '9') | |
998 | { | |
999 | processor = pchar - '0'; | |
1000 | if (**str >= '0' && **str <= '9') | |
1001 | { | |
1002 | processor = processor * 10 + *(*str)++ - '0'; | |
1003 | if (processor > 15) | |
1004 | { | |
1005 | inst.error = "Illegal co-processor number"; | |
1006 | return FAIL; | |
1007 | } | |
1008 | } | |
1009 | } | |
1010 | else | |
1011 | { | |
1012 | inst.error = "Bad or missing co-processor number"; | |
1013 | return FAIL; | |
1014 | } | |
1015 | ||
1016 | inst.instruction |= processor << 8; | |
1017 | return SUCCESS; | |
1018 | } | |
1019 | ||
1020 | static int | |
1021 | cp_opc_expr (str, where, length) | |
1022 | char **str; | |
1023 | int where; | |
1024 | int length; | |
1025 | { | |
1026 | expressionS expr; | |
1027 | ||
1028 | while (**str == ' ') | |
1029 | (*str)++; | |
1030 | ||
1031 | memset (&expr, '\0', sizeof (expr)); | |
1032 | ||
1033 | if (my_get_expression (&expr, str)) | |
1034 | return FAIL; | |
1035 | if (expr.X_op != O_constant) | |
1036 | { | |
1037 | inst.error = "bad or missing expression"; | |
1038 | return FAIL; | |
1039 | } | |
1040 | ||
1041 | if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number) | |
1042 | { | |
1043 | inst.error = "immediate co-processor expression too large"; | |
1044 | return FAIL; | |
1045 | } | |
1046 | ||
1047 | inst.instruction |= expr.X_add_number << where; | |
1048 | return SUCCESS; | |
1049 | } | |
1050 | ||
1051 | static int | |
1052 | cp_reg_required_here (str, where) | |
1053 | char **str; | |
1054 | int where; | |
1055 | { | |
1056 | int reg; | |
1057 | char *start = *str; | |
1058 | ||
1059 | if ((reg = arm_reg_parse (str)) != FAIL && cp_register (reg)) | |
1060 | { | |
1061 | reg &= 15; | |
1062 | inst.instruction |= reg << where; | |
1063 | return reg; | |
1064 | } | |
1065 | ||
1066 | /* In the few cases where we might be able to accept something else | |
1067 | this error can be overridden */ | |
1068 | inst.error = "Co-processor register expected"; | |
1069 | ||
1070 | /* Restore the start point */ | |
1071 | *str = start; | |
1072 | return FAIL; | |
1073 | } | |
1074 | ||
1075 | static int | |
1076 | fp_reg_required_here (str, where) | |
1077 | char **str; | |
1078 | int where; | |
1079 | { | |
1080 | int reg; | |
1081 | char *start = *str; | |
1082 | ||
1083 | if ((reg = arm_reg_parse (str)) != FAIL && fp_register (reg)) | |
1084 | { | |
1085 | reg &= 7; | |
1086 | inst.instruction |= reg << where; | |
1087 | return reg; | |
1088 | } | |
1089 | ||
1090 | /* In the few cases where we might be able to accept something else | |
1091 | this error can be overridden */ | |
1092 | inst.error = "Floating point register expected"; | |
1093 | ||
1094 | /* Restore the start point */ | |
1095 | *str = start; | |
1096 | return FAIL; | |
1097 | } | |
1098 | ||
1099 | static int | |
1100 | cp_address_offset (str) | |
1101 | char **str; | |
1102 | { | |
1103 | int offset; | |
1104 | ||
1105 | while (**str == ' ') | |
1106 | (*str)++; | |
1107 | ||
1108 | if (**str != '#') | |
1109 | { | |
1110 | inst.error = "immediate expression expected"; | |
1111 | return FAIL; | |
1112 | } | |
1113 | ||
1114 | (*str)++; | |
1115 | if (my_get_expression (&inst.reloc.exp, str)) | |
1116 | return FAIL; | |
1117 | if (inst.reloc.exp.X_op == O_constant) | |
1118 | { | |
1119 | offset = inst.reloc.exp.X_add_number; | |
1120 | if (offset & 3) | |
1121 | { | |
1122 | inst.error = "co-processor address must be word aligned"; | |
1123 | return FAIL; | |
1124 | } | |
1125 | ||
1126 | if (offset > 1023 || offset < -1023) | |
1127 | { | |
1128 | inst.error = "offset too large"; | |
1129 | return FAIL; | |
1130 | } | |
1131 | ||
1132 | if (offset >= 0) | |
1133 | inst.instruction |= INDEX_UP; | |
1134 | else | |
1135 | offset = -offset; | |
1136 | ||
1137 | inst.instruction |= offset >> 2; | |
1138 | } | |
1139 | else | |
1140 | inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; | |
1141 | ||
1142 | return SUCCESS; | |
1143 | } | |
1144 | ||
1145 | static int | |
1146 | cp_address_required_here (str) | |
1147 | char **str; | |
1148 | { | |
1149 | char *p = *str; | |
1150 | int pre_inc = 0; | |
1151 | int write_back = 0; | |
1152 | ||
1153 | if (*p == '[') | |
1154 | { | |
1155 | int reg; | |
1156 | ||
1157 | p++; | |
1158 | while (*p == ' ') | |
1159 | p++; | |
1160 | ||
1161 | if ((reg = reg_required_here (&p, 16)) == FAIL) | |
1162 | { | |
1163 | inst.error = "Register required"; | |
1164 | return FAIL; | |
1165 | } | |
1166 | ||
1167 | while (*p == ' ') | |
1168 | p++; | |
1169 | ||
1170 | if (*p == ']') | |
1171 | { | |
1172 | p++; | |
1173 | if (skip_past_comma (&p) == SUCCESS) | |
1174 | { | |
1175 | /* [Rn], #expr */ | |
1176 | write_back = WRITE_BACK; | |
1177 | if (reg == REG_PC) | |
1178 | { | |
1179 | inst.error = "pc may not be used in post-increment"; | |
1180 | return FAIL; | |
1181 | } | |
1182 | ||
1183 | if (cp_address_offset (&p) == FAIL) | |
1184 | return FAIL; | |
1185 | } | |
1186 | else | |
1187 | pre_inc = PRE_INDEX | INDEX_UP; | |
1188 | } | |
1189 | else | |
1190 | { | |
1191 | /* '['Rn, #expr']'[!] */ | |
1192 | ||
1193 | if (skip_past_comma (&p) == FAIL) | |
1194 | { | |
1195 | inst.error = "pre-indexed expression expected"; | |
1196 | return FAIL; | |
1197 | } | |
1198 | ||
1199 | pre_inc = PRE_INDEX; | |
1200 | if (cp_address_offset (&p) == FAIL) | |
1201 | return FAIL; | |
1202 | ||
1203 | while (*p == ' ') | |
1204 | p++; | |
1205 | ||
1206 | if (*p++ != ']') | |
1207 | { | |
1208 | inst.error = "missing ]"; | |
1209 | return FAIL; | |
1210 | } | |
1211 | ||
1212 | while (*p == ' ') | |
1213 | p++; | |
1214 | ||
1215 | if (*p == '!') | |
1216 | { | |
1217 | if (reg == REG_PC) | |
1218 | { | |
1219 | inst.error = "pc may not be used with write-back"; | |
1220 | return FAIL; | |
1221 | } | |
1222 | ||
1223 | p++; | |
1224 | write_back = WRITE_BACK; | |
1225 | } | |
1226 | } | |
1227 | } | |
1228 | else | |
1229 | { | |
1230 | if (my_get_expression (&inst.reloc.exp, &p)) | |
1231 | return FAIL; | |
1232 | ||
1233 | inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; | |
1234 | inst.reloc.exp.X_add_number -= 8; /* PC rel adjust */ | |
1235 | inst.reloc.pc_rel = 1; | |
1236 | inst.instruction |= (REG_PC << 16); | |
1237 | } | |
1238 | ||
1239 | inst.instruction |= write_back | pre_inc; | |
1240 | *str = p; | |
1241 | return SUCCESS; | |
1242 | } | |
1243 | ||
1244 | static void | |
1245 | do_nop (str, flags) | |
1246 | char *str; | |
1247 | unsigned long flags; | |
1248 | { | |
1249 | /* Do nothing really */ | |
1250 | inst.instruction |= flags; /* This is pointless */ | |
1251 | end_of_line (str); | |
1252 | return; | |
1253 | } | |
1254 | ||
1255 | static void | |
1256 | do_mrs (str, flags) | |
1257 | char *str; | |
1258 | unsigned long flags; | |
1259 | { | |
1260 | /* Only one syntax */ | |
1261 | while (*str == ' ') | |
1262 | str++; | |
1263 | ||
1264 | if (reg_required_here (&str, 12) == FAIL) | |
1265 | { | |
1266 | inst.error = bad_args; | |
1267 | return; | |
1268 | } | |
1269 | ||
1270 | if (skip_past_comma (&str) == FAIL | |
1271 | || psr_required_here (&str, 22) == FAIL) | |
1272 | { | |
1273 | inst.error = "<psr> expected"; | |
1274 | return; | |
1275 | } | |
1276 | ||
1277 | inst.instruction |= flags; | |
1278 | end_of_line (str); | |
1279 | return; | |
1280 | } | |
1281 | ||
1282 | static void | |
1283 | do_msr (str, flags) | |
1284 | char *str; | |
1285 | unsigned long flags; | |
1286 | { | |
1287 | int psr, psrf, reg; | |
1288 | /* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression" */ | |
1289 | ||
1290 | while (*str == ' ') | |
1291 | str++; | |
1292 | ||
1293 | if ((psr = psr_required_here (&str, 22)) != FAIL) | |
1294 | { | |
1295 | inst.instruction |= PSR_ALL; | |
1296 | /* Sytax should be "<psr>, Rm" */ | |
1297 | if (skip_past_comma (&str) == FAIL | |
1298 | || (reg = reg_required_here (&str, 0)) == FAIL) | |
1299 | { | |
1300 | inst.error = bad_args; | |
1301 | return; | |
1302 | } | |
1303 | } | |
1304 | else if ((psrf = psrf_required_here (&str, 22)) != FAIL) | |
1305 | /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */ | |
1306 | { | |
1307 | if (skip_past_comma (&str) == FAIL) | |
1308 | { | |
1309 | inst.error = bad_args; | |
1310 | return; | |
1311 | } | |
1312 | if ((reg = reg_required_here (&str, 0)) != FAIL) | |
1313 | ; | |
1314 | /* Immediate expression */ | |
1315 | else if (*(str++) == '#') | |
1316 | { | |
1317 | inst.error = NULL; | |
1318 | if (my_get_expression (&inst.reloc.exp, &str)) | |
1319 | { | |
1320 | inst.error = "Register or shift expression expected"; | |
1321 | return; | |
1322 | } | |
1323 | ||
1324 | if (inst.reloc.exp.X_add_symbol) | |
1325 | { | |
1326 | inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; | |
1327 | inst.reloc.pc_rel = 0; | |
1328 | } | |
1329 | else | |
1330 | { | |
1331 | int value = validate_immediate (inst.reloc.exp.X_add_number); | |
1332 | if (value == FAIL) | |
1333 | { | |
1334 | inst.error = "Invalid constant"; | |
1335 | return; | |
1336 | } | |
1337 | ||
1338 | inst.instruction |= value; | |
1339 | } | |
1340 | ||
1341 | flags |= INST_IMMEDIATE; | |
1342 | } | |
1343 | else | |
1344 | { | |
1345 | inst.error = "Error: the other"; | |
1346 | return; | |
1347 | } | |
1348 | } | |
1349 | else | |
1350 | { | |
1351 | inst.error = bad_args; | |
1352 | return; | |
1353 | } | |
1354 | ||
1355 | inst.error = NULL; | |
1356 | inst.instruction |= flags; | |
1357 | end_of_line (str); | |
1358 | return; | |
1359 | } | |
1360 | ||
1361 | /* Long Multiply Parser | |
1362 | UMULL RdLo, RdHi, Rm, Rs | |
1363 | SMULL RdLo, RdHi, Rm, Rs | |
1364 | UMLAL RdLo, RdHi, Rm, Rs | |
1365 | SMLAL RdLo, RdHi, Rm, Rs | |
1366 | */ | |
1367 | static void | |
1368 | do_mull (str, flags) | |
1369 | char *str; | |
1370 | unsigned long flags; | |
1371 | { | |
1372 | int rdlo, rdhi, rm, rs; | |
1373 | ||
1374 | /* only one format "rdlo, rdhi, rm, rs" */ | |
1375 | while (*str == ' ') | |
1376 | str++; | |
1377 | ||
1378 | if ((rdlo = reg_required_here (&str, 12)) == FAIL) | |
1379 | { | |
1380 | inst.error = bad_args; | |
1381 | return; | |
1382 | } | |
1383 | ||
1384 | if (skip_past_comma (&str) == FAIL | |
1385 | || (rdhi = reg_required_here (&str, 16)) == FAIL) | |
1386 | { | |
1387 | inst.error = bad_args; | |
1388 | return; | |
1389 | } | |
1390 | ||
1391 | if (skip_past_comma (&str) == FAIL | |
1392 | || (rm = reg_required_here (&str, 0)) == FAIL) | |
1393 | { | |
1394 | inst.error = bad_args; | |
1395 | return; | |
1396 | } | |
1397 | ||
1398 | /* rdhi, rdlo and rm must all be different */ | |
1399 | if (rdlo == rdhi || rdlo == rm || rdhi == rm) | |
1400 | as_tsktsk ("rdhi, rdlo and rm must all be different"); | |
1401 | ||
1402 | if (skip_past_comma (&str) == FAIL | |
1403 | || (rs = reg_required_here (&str, 8)) == FAIL) | |
1404 | { | |
1405 | inst.error = bad_args; | |
1406 | return; | |
1407 | } | |
1408 | ||
1409 | if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC) | |
1410 | { | |
1411 | inst.error = bad_pc; | |
1412 | return; | |
1413 | } | |
1414 | ||
1415 | inst.instruction |= flags; | |
1416 | end_of_line (str); | |
1417 | return; | |
1418 | } | |
1419 | ||
1420 | static void | |
1421 | do_mul (str, flags) | |
1422 | char *str; | |
1423 | unsigned long flags; | |
1424 | { | |
1425 | int rd, rm; | |
1426 | ||
1427 | /* only one format "rd, rm, rs" */ | |
1428 | while (*str == ' ') | |
1429 | str++; | |
1430 | ||
1431 | if ((rd = reg_required_here (&str, 16)) == FAIL) | |
1432 | { | |
1433 | inst.error = bad_args; | |
1434 | return; | |
1435 | } | |
1436 | ||
1437 | if (rd == REG_PC) | |
1438 | { | |
1439 | inst.error = bad_pc; | |
1440 | return; | |
1441 | } | |
1442 | ||
1443 | if (skip_past_comma (&str) == FAIL | |
1444 | || (rm = reg_required_here (&str, 0)) == FAIL) | |
1445 | { | |
1446 | inst.error = bad_args; | |
1447 | return; | |
1448 | } | |
1449 | ||
1450 | if (rm == REG_PC) | |
1451 | { | |
1452 | inst.error = bad_pc; | |
1453 | return; | |
1454 | } | |
1455 | ||
1456 | if (rm == rd) | |
1457 | as_tsktsk ("rd and rm should be different in mul"); | |
1458 | ||
1459 | if (skip_past_comma (&str) == FAIL | |
1460 | || (rm = reg_required_here (&str, 8)) == FAIL) | |
1461 | { | |
1462 | inst.error = bad_args; | |
1463 | return; | |
1464 | } | |
1465 | ||
1466 | if (rm == REG_PC) | |
1467 | { | |
1468 | inst.error = bad_pc; | |
1469 | return; | |
1470 | } | |
1471 | ||
1472 | inst.instruction |= flags; | |
1473 | end_of_line (str); | |
1474 | return; | |
1475 | } | |
1476 | ||
1477 | static void | |
1478 | do_mla (str, flags) | |
1479 | char *str; | |
1480 | unsigned long flags; | |
1481 | { | |
1482 | int rd, rm; | |
1483 | ||
1484 | /* only one format "rd, rm, rs, rn" */ | |
1485 | while (*str == ' ') | |
1486 | str++; | |
1487 | ||
1488 | if ((rd = reg_required_here (&str, 16)) == FAIL) | |
1489 | { | |
1490 | inst.error = bad_args; | |
1491 | return; | |
1492 | } | |
1493 | ||
1494 | if (rd == REG_PC) | |
1495 | { | |
1496 | inst.error = bad_pc; | |
1497 | return; | |
1498 | } | |
1499 | ||
1500 | if (skip_past_comma (&str) == FAIL | |
1501 | || (rm = reg_required_here (&str, 0)) == FAIL) | |
1502 | { | |
1503 | inst.error = bad_args; | |
1504 | return; | |
1505 | } | |
1506 | ||
1507 | if (rm == REG_PC) | |
1508 | { | |
1509 | inst.error = bad_pc; | |
1510 | return; | |
1511 | } | |
1512 | ||
1513 | if (rm == rd) | |
1514 | as_tsktsk ("rd and rm should be different in mla"); | |
1515 | ||
1516 | if (skip_past_comma (&str) == FAIL | |
1517 | || (rd = reg_required_here (&str, 8)) == FAIL | |
1518 | || skip_past_comma (&str) == FAIL | |
1519 | || (rm = reg_required_here (&str, 12)) == FAIL) | |
1520 | { | |
1521 | inst.error = bad_args; | |
1522 | return; | |
1523 | } | |
1524 | ||
1525 | if (rd == REG_PC || rm == REG_PC) | |
1526 | { | |
1527 | inst.error = bad_pc; | |
1528 | return; | |
1529 | } | |
1530 | ||
1531 | inst.instruction |= flags; | |
1532 | end_of_line (str); | |
1533 | return; | |
1534 | } | |
1535 | ||
1536 | /* Returns the index into fp_values of a floating point number, or -1 if | |
1537 | not in the table. */ | |
1538 | static int | |
1539 | my_get_float_expression (str) | |
1540 | char **str; | |
1541 | { | |
1542 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
1543 | char *save_in; | |
1544 | expressionS exp; | |
1545 | int i, j; | |
1546 | ||
1547 | memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE)); | |
1548 | /* Look for a raw floating point number */ | |
1549 | if ((save_in = atof_ieee (*str, 'x', words)) != NULL | |
1550 | && (is_end_of_line [(int)(*save_in)] || *save_in == '\0')) | |
1551 | { | |
1552 | for (i = 0; i < NUM_FLOAT_VALS; i++) | |
1553 | { | |
1554 | for (j = 0; j < MAX_LITTLENUMS; j++) | |
1555 | { | |
1556 | if (words[j] != fp_values[i][j]) | |
1557 | break; | |
1558 | } | |
1559 | ||
1560 | if (j == MAX_LITTLENUMS) | |
1561 | { | |
1562 | *str = save_in; | |
1563 | return i; | |
1564 | } | |
1565 | } | |
1566 | } | |
1567 | ||
1568 | /* Try and parse a more complex expression, this will probably fail | |
1569 | unless the code uses a floating point prefix (eg "0f") */ | |
1570 | save_in = input_line_pointer; | |
1571 | input_line_pointer = *str; | |
1572 | if (expression (&exp) == absolute_section | |
1573 | && exp.X_op == O_big | |
1574 | && exp.X_add_number < 0) | |
1575 | { | |
1576 | if (gen_to_words (words, 6, (long)15) == 0) | |
1577 | { | |
1578 | for (i = 0; i < NUM_FLOAT_VALS; i++) | |
1579 | { | |
1580 | for (j = 0; j < MAX_LITTLENUMS; j++) | |
1581 | { | |
1582 | if (words[j] != fp_values[i][j]) | |
1583 | break; | |
1584 | } | |
1585 | ||
1586 | if (j == MAX_LITTLENUMS) | |
1587 | { | |
1588 | *str = input_line_pointer; | |
1589 | input_line_pointer = save_in; | |
1590 | return i; | |
1591 | } | |
1592 | } | |
1593 | } | |
1594 | } | |
1595 | ||
1596 | *str = input_line_pointer; | |
1597 | input_line_pointer = save_in; | |
1598 | return -1; | |
1599 | } | |
1600 | ||
1601 | /* Return true if anything in the expression is a bignum */ | |
1602 | static int | |
1603 | walk_no_bignums (sp) | |
1604 | symbolS *sp; | |
1605 | { | |
1606 | if (sp->sy_value.X_op == O_big) | |
1607 | return 1; | |
1608 | ||
1609 | if (sp->sy_value.X_add_symbol) | |
1610 | { | |
1611 | return (walk_no_bignums (sp->sy_value.X_add_symbol) | |
1612 | || (sp->sy_value.X_op_symbol | |
1613 | && walk_no_bignums (sp->sy_value.X_op_symbol))); | |
1614 | } | |
1615 | ||
1616 | return 0; | |
1617 | } | |
1618 | ||
1619 | static int | |
1620 | my_get_expression (ep, str) | |
1621 | expressionS *ep; | |
1622 | char **str; | |
1623 | { | |
1624 | char *save_in; | |
1625 | segT seg; | |
1626 | ||
1627 | save_in = input_line_pointer; | |
1628 | input_line_pointer = *str; | |
1629 | seg = expression (ep); | |
1630 | if (seg != absolute_section | |
1631 | && seg != text_section | |
1632 | && seg != data_section | |
1633 | && seg != bss_section | |
1634 | && seg != undefined_section) | |
1635 | { | |
1636 | inst.error = "bad_segment"; | |
1637 | *str = input_line_pointer; | |
1638 | input_line_pointer = save_in; | |
1639 | return 1; | |
1640 | } | |
1641 | ||
1642 | /* Get rid of any bignums now, so that we don't generate an error for which | |
1643 | we can't establish a line number later on. Big numbers are never valid | |
1644 | in instructions, which is where is routine is always called. */ | |
1645 | if (ep->X_op == O_big | |
1646 | || (ep->X_add_symbol | |
1647 | && (walk_no_bignums (ep->X_add_symbol) | |
1648 | || (ep->X_op_symbol | |
1649 | && walk_no_bignums (ep->X_op_symbol))))) | |
1650 | { | |
1651 | inst.error = "Invalid constant"; | |
1652 | *str = input_line_pointer; | |
1653 | input_line_pointer = save_in; | |
1654 | return 1; | |
1655 | } | |
1656 | ||
1657 | *str = input_line_pointer; | |
1658 | input_line_pointer = save_in; | |
1659 | return 0; | |
1660 | } | |
1661 | ||
1662 | /* unrestrict should be one if <shift> <register> is permitted for this | |
1663 | instruction */ | |
1664 | ||
1665 | static int | |
1666 | decode_shift (str, unrestrict) | |
1667 | char **str; | |
1668 | int unrestrict; | |
1669 | { | |
1670 | struct asm_shift *shft; | |
1671 | char *p; | |
1672 | char c; | |
1673 | ||
1674 | while (**str == ' ') | |
1675 | (*str)++; | |
1676 | ||
1677 | for (p = *str; isalpha (*p); p++) | |
1678 | ; | |
1679 | ||
1680 | if (p == *str) | |
1681 | { | |
1682 | inst.error = "Shift expression expected"; | |
1683 | return FAIL; | |
1684 | } | |
1685 | ||
1686 | c = *p; | |
1687 | *p = '\0'; | |
1688 | shft = (struct asm_shift *) hash_find (arm_shift_hsh, *str); | |
1689 | *p = c; | |
1690 | if (shft) | |
1691 | { | |
1692 | if (!strcmp (*str, "rrx")) | |
1693 | { | |
1694 | *str = p; | |
1695 | inst.instruction |= shft->value; | |
1696 | return SUCCESS; | |
1697 | } | |
1698 | ||
1699 | while (*p == ' ') | |
1700 | p++; | |
1701 | ||
1702 | if (unrestrict && reg_required_here (&p, 8) != FAIL) | |
1703 | { | |
1704 | inst.instruction |= shft->value | SHIFT_BY_REG; | |
1705 | *str = p; | |
1706 | return SUCCESS; | |
1707 | } | |
1708 | else if (*p == '#') | |
1709 | { | |
1710 | inst.error = NULL; | |
1711 | p++; | |
1712 | if (my_get_expression (&inst.reloc.exp, &p)) | |
1713 | return FAIL; | |
1714 | ||
1715 | /* Validate some simple #expressions */ | |
1716 | if (! inst.reloc.exp.X_add_symbol) | |
1717 | { | |
1718 | int num = inst.reloc.exp.X_add_number; | |
1719 | if (num < 0 || num > 32 | |
1720 | || (num == 32 | |
1721 | && (shft->value == 0 || shft->value == 0x60))) | |
1722 | { | |
1723 | inst.error = "Invalid immediate shift"; | |
1724 | return FAIL; | |
1725 | } | |
1726 | ||
1727 | /* Shifts of zero should be converted to lsl (which is zero)*/ | |
1728 | if (num == 0) | |
1729 | { | |
1730 | *str = p; | |
1731 | return SUCCESS; | |
1732 | } | |
1733 | ||
1734 | /* Shifts of 32 are encoded as 0, for those shifts that | |
1735 | support it. */ | |
1736 | if (num == 32) | |
1737 | num = 0; | |
1738 | ||
1739 | inst.instruction |= (num << 7) | shft->value; | |
1740 | *str = p; | |
1741 | return SUCCESS; | |
1742 | } | |
1743 | ||
1744 | inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; | |
1745 | inst.reloc.pc_rel = 0; | |
1746 | inst.instruction |= shft->value; | |
1747 | *str = p; | |
1748 | return SUCCESS; | |
1749 | } | |
1750 | else | |
1751 | { | |
1752 | inst.error = unrestrict ? "shift requires register or #expression" | |
1753 | : "shift requires #expression"; | |
1754 | *str = p; | |
1755 | return FAIL; | |
1756 | } | |
1757 | } | |
1758 | ||
1759 | inst.error = "Shift expression expected"; | |
1760 | return FAIL; | |
1761 | } | |
1762 | ||
1763 | /* Do those data_ops which can take a negative immediate constant */ | |
1764 | /* by altering the instuction. A bit of a hack really */ | |
1765 | /* MOV <-> MVN | |
1766 | AND <-> BIC | |
1767 | ADC <-> SBC | |
1768 | by inverting the second operand, and | |
1769 | ADD <-> SUB | |
1770 | CMP <-> CMN | |
1771 | by negating the second operand. | |
1772 | */ | |
1773 | static int | |
1774 | negate_data_op (instruction, value) | |
1775 | unsigned long *instruction; | |
1776 | unsigned long value; | |
1777 | { | |
1778 | int op, new_inst; | |
1779 | unsigned long negated, inverted; | |
1780 | ||
1781 | negated = validate_immediate (-value); | |
1782 | inverted = validate_immediate (~value); | |
1783 | ||
1784 | op = (*instruction >> DATA_OP_SHIFT) & 0xf; | |
1785 | switch (op) | |
1786 | { | |
1787 | /* First negates */ | |
1788 | case OPCODE_SUB: /* ADD <-> SUB */ | |
1789 | new_inst = OPCODE_ADD; | |
1790 | value = negated; | |
1791 | break; | |
1792 | ||
1793 | case OPCODE_ADD: | |
1794 | new_inst = OPCODE_SUB; | |
1795 | value = negated; | |
1796 | break; | |
1797 | ||
1798 | case OPCODE_CMP: /* CMP <-> CMN */ | |
1799 | new_inst = OPCODE_CMN; | |
1800 | value = negated; | |
1801 | break; | |
1802 | ||
1803 | case OPCODE_CMN: | |
1804 | new_inst = OPCODE_CMP; | |
1805 | value = negated; | |
1806 | break; | |
1807 | ||
1808 | /* Now Inverted ops */ | |
1809 | case OPCODE_MOV: /* MOV <-> MVN */ | |
1810 | new_inst = OPCODE_MVN; | |
1811 | value = inverted; | |
1812 | break; | |
1813 | ||
1814 | case OPCODE_MVN: | |
1815 | new_inst = OPCODE_MOV; | |
1816 | value = inverted; | |
1817 | break; | |
1818 | ||
1819 | case OPCODE_AND: /* AND <-> BIC */ | |
1820 | new_inst = OPCODE_BIC; | |
1821 | value = inverted; | |
1822 | break; | |
1823 | ||
1824 | case OPCODE_BIC: | |
1825 | new_inst = OPCODE_AND; | |
1826 | value = inverted; | |
1827 | break; | |
1828 | ||
1829 | case OPCODE_ADC: /* ADC <-> SBC */ | |
1830 | new_inst = OPCODE_SBC; | |
1831 | value = inverted; | |
1832 | break; | |
1833 | ||
1834 | case OPCODE_SBC: | |
1835 | new_inst = OPCODE_ADC; | |
1836 | value = inverted; | |
1837 | break; | |
1838 | ||
1839 | /* We cannot do anything */ | |
1840 | default: | |
1841 | return FAIL; | |
1842 | } | |
1843 | ||
1844 | if (value == FAIL) | |
1845 | return FAIL; | |
1846 | ||
1847 | *instruction &= OPCODE_MASK; | |
1848 | *instruction |= new_inst << DATA_OP_SHIFT; | |
1849 | return value; | |
1850 | } | |
1851 | ||
1852 | static int | |
1853 | data_op2 (str) | |
1854 | char **str; | |
1855 | { | |
1856 | int value; | |
1857 | expressionS expr; | |
1858 | ||
1859 | while (**str == ' ') | |
1860 | (*str)++; | |
1861 | ||
1862 | if (reg_required_here (str, 0) != FAIL) | |
1863 | { | |
1864 | if (skip_past_comma (str) == SUCCESS) | |
1865 | { | |
1866 | /* Shift operation on register */ | |
1867 | return decode_shift (str, NO_SHIFT_RESTRICT); | |
1868 | } | |
1869 | return SUCCESS; | |
1870 | } | |
1871 | else | |
1872 | { | |
1873 | /* Immediate expression */ | |
1874 | if (*((*str)++) == '#') | |
1875 | { | |
1876 | inst.error = NULL; | |
1877 | if (my_get_expression (&inst.reloc.exp, str)) | |
1878 | return FAIL; | |
1879 | ||
1880 | if (inst.reloc.exp.X_add_symbol) | |
1881 | { | |
1882 | inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; | |
1883 | inst.reloc.pc_rel = 0; | |
1884 | } | |
1885 | else | |
1886 | { | |
1887 | if (skip_past_comma (str) == SUCCESS) | |
1888 | { | |
1889 | /* #x, y -- ie explicit rotation by Y */ | |
1890 | if (my_get_expression (&expr, str)) | |
1891 | return FAIL; | |
1892 | ||
1893 | if (expr.X_op != O_constant) | |
1894 | { | |
1895 | inst.error = "Constant expression expected"; | |
1896 | return FAIL; | |
1897 | } | |
1898 | ||
1899 | /* Rotate must be a multiple of 2 */ | |
1900 | if (((unsigned) expr.X_add_number) > 30 | |
1901 | || (expr.X_add_number & 1) != 0 | |
1902 | || ((unsigned) inst.reloc.exp.X_add_number) > 255) | |
1903 | { | |
1904 | inst.error = "Invalid constant"; | |
1905 | return FAIL; | |
1906 | } | |
1907 | inst.instruction |= INST_IMMEDIATE; | |
1908 | inst.instruction |= inst.reloc.exp.X_add_number; | |
1909 | inst.instruction |= expr.X_add_number << 7; | |
1910 | return SUCCESS; | |
1911 | } | |
1912 | ||
1913 | /* Implicit rotation, select a suitable one */ | |
1914 | value = validate_immediate (inst.reloc.exp.X_add_number); | |
1915 | ||
1916 | if (value == FAIL) | |
1917 | { | |
1918 | /* Can't be done, perhaps the code reads something like | |
1919 | "add Rd, Rn, #-n", where "sub Rd, Rn, #n" would be ok */ | |
1920 | if ((value = negate_data_op (&inst.instruction, | |
1921 | inst.reloc.exp.X_add_number)) | |
1922 | == FAIL) | |
1923 | { | |
1924 | inst.error = "Invalid constant"; | |
1925 | return FAIL; | |
1926 | } | |
1927 | } | |
1928 | ||
1929 | inst.instruction |= value; | |
1930 | } | |
1931 | ||
1932 | inst.instruction |= INST_IMMEDIATE; | |
1933 | return SUCCESS; | |
1934 | } | |
1935 | ||
1936 | inst.error = "Register or shift expression expected"; | |
1937 | return FAIL; | |
1938 | } | |
1939 | } | |
1940 | ||
1941 | static int | |
1942 | fp_op2 (str, flags) | |
1943 | char **str; | |
1944 | unsigned long flags; | |
1945 | { | |
1946 | while (**str == ' ') | |
1947 | (*str)++; | |
1948 | ||
1949 | if (fp_reg_required_here (str, 0) != FAIL) | |
1950 | return SUCCESS; | |
1951 | else | |
1952 | { | |
1953 | /* Immediate expression */ | |
1954 | if (*((*str)++) == '#') | |
1955 | { | |
1956 | int i; | |
1957 | ||
1958 | inst.error = NULL; | |
1959 | while (**str == ' ') | |
1960 | (*str)++; | |
1961 | ||
1962 | /* First try and match exact strings, this is to guarantee that | |
1963 | some formats will work even for cross assembly */ | |
1964 | ||
1965 | for (i = 0; fp_const[i]; i++) | |
1966 | { | |
1967 | if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0) | |
1968 | { | |
1969 | char *start = *str; | |
1970 | ||
1971 | *str += strlen (fp_const[i]); | |
1972 | if (is_end_of_line[(int)**str] || **str == '\0') | |
1973 | { | |
1974 | inst.instruction |= i + 8; | |
1975 | return SUCCESS; | |
1976 | } | |
1977 | *str = start; | |
1978 | } | |
1979 | } | |
1980 | ||
1981 | /* Just because we didn't get a match doesn't mean that the | |
1982 | constant isn't valid, just that it is in a format that we | |
1983 | don't automatically recognize. Try parsing it with | |
1984 | the standard expression routines. */ | |
1985 | if ((i = my_get_float_expression (str)) >= 0) | |
1986 | { | |
1987 | inst.instruction |= i + 8; | |
1988 | return SUCCESS; | |
1989 | } | |
1990 | ||
1991 | inst.error = "Invalid floating point immediate expression"; | |
1992 | return FAIL; | |
1993 | } | |
1994 | inst.error = "Floating point register or immediate expression expected"; | |
1995 | return FAIL; | |
1996 | } | |
1997 | } | |
1998 | ||
1999 | static void | |
2000 | do_arit (str, flags) | |
2001 | char *str; | |
2002 | unsigned long flags; | |
2003 | { | |
2004 | while (*str == ' ') | |
2005 | str++; | |
2006 | ||
2007 | if (reg_required_here (&str, 12) == FAIL | |
2008 | || skip_past_comma (&str) == FAIL | |
2009 | || reg_required_here (&str, 16) == FAIL | |
2010 | || skip_past_comma (&str) == FAIL | |
2011 | || data_op2 (&str) == FAIL) | |
2012 | { | |
2013 | if (!inst.error) | |
2014 | inst.error = bad_args; | |
2015 | return; | |
2016 | } | |
2017 | ||
2018 | inst.instruction |= flags; | |
2019 | end_of_line (str); | |
2020 | return; | |
2021 | } | |
2022 | ||
2023 | static void | |
2024 | do_adr (str, flags) | |
2025 | char *str; | |
2026 | unsigned long flags; | |
2027 | { | |
2028 | /* This is a pseudo-op of the form "adr rd, label" to be converted into | |
2029 | a relative address of the form add rd, pc, #label-.-8 */ | |
2030 | ||
2031 | while (*str == ' ') | |
2032 | str++; | |
2033 | ||
2034 | if (reg_required_here (&str, 12) == FAIL | |
2035 | || skip_past_comma (&str) == FAIL | |
2036 | || my_get_expression (&inst.reloc.exp, &str)) | |
2037 | { | |
2038 | if (!inst.error) | |
2039 | inst.error = bad_args; | |
2040 | return; | |
2041 | } | |
2042 | /* Frag hacking will turn this into a sub instruction if the offset turns | |
2043 | out to be negative. */ | |
2044 | inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; | |
2045 | inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */ | |
2046 | inst.reloc.pc_rel = 1; | |
2047 | inst.instruction |= flags; | |
2048 | end_of_line (str); | |
2049 | return; | |
2050 | } | |
2051 | ||
2052 | static void | |
2053 | do_cmp (str, flags) | |
2054 | char *str; | |
2055 | unsigned long flags; | |
2056 | { | |
2057 | while (*str == ' ') | |
2058 | str++; | |
2059 | ||
2060 | if (reg_required_here (&str, 16) == FAIL) | |
2061 | { | |
2062 | if (!inst.error) | |
2063 | inst.error = bad_args; | |
2064 | return; | |
2065 | } | |
2066 | ||
2067 | if (skip_past_comma (&str) == FAIL | |
2068 | || data_op2 (&str) == FAIL) | |
2069 | { | |
2070 | if (!inst.error) | |
2071 | inst.error = bad_args; | |
2072 | return; | |
2073 | } | |
2074 | ||
2075 | inst.instruction |= flags; | |
2076 | if ((flags & 0x0000f000) == 0) | |
2077 | inst.instruction |= 0x00100000; | |
2078 | ||
2079 | end_of_line (str); | |
2080 | return; | |
2081 | } | |
2082 | ||
2083 | static void | |
2084 | do_mov (str, flags) | |
2085 | char *str; | |
2086 | unsigned long flags; | |
2087 | { | |
2088 | while (*str == ' ') | |
2089 | str++; | |
2090 | ||
2091 | if (reg_required_here (&str, 12) == FAIL) | |
2092 | { | |
2093 | if (!inst.error) | |
2094 | inst.error = bad_args; | |
2095 | return; | |
2096 | } | |
2097 | ||
2098 | if (skip_past_comma (&str) == FAIL | |
2099 | || data_op2 (&str) == FAIL) | |
2100 | { | |
2101 | if (!inst.error) | |
2102 | inst.error = bad_args; | |
2103 | return; | |
2104 | } | |
2105 | ||
2106 | inst.instruction |= flags; | |
2107 | end_of_line (str); | |
2108 | return; | |
2109 | } | |
2110 | ||
2111 | static int | |
2112 | ldst_extend (str) | |
2113 | char **str; | |
2114 | { | |
2115 | int add = INDEX_UP; | |
2116 | ||
2117 | switch (**str) | |
2118 | { | |
2119 | case '#': | |
2120 | (*str)++; | |
2121 | if (my_get_expression (&inst.reloc.exp, str)) | |
2122 | return FAIL; | |
2123 | ||
2124 | if (inst.reloc.exp.X_op == O_constant) | |
2125 | { | |
2126 | int value = inst.reloc.exp.X_add_number; | |
2127 | ||
2128 | if (value < -4095 || value > 4095) | |
2129 | { | |
2130 | inst.error = "address offset too large"; | |
2131 | return FAIL; | |
2132 | } | |
2133 | ||
2134 | if (value < 0) | |
2135 | { | |
2136 | value = -value; | |
2137 | add = 0; | |
2138 | } | |
2139 | ||
2140 | inst.instruction |= add | value; | |
2141 | } | |
2142 | else | |
2143 | { | |
2144 | inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM; | |
2145 | inst.reloc.pc_rel = 0; | |
2146 | } | |
2147 | return SUCCESS; | |
2148 | ||
2149 | case '-': | |
2150 | add = 0; /* and fall through */ | |
2151 | case '+': | |
2152 | (*str)++; /* and fall through */ | |
2153 | default: | |
2154 | if (reg_required_here (str, 0) == FAIL) | |
2155 | { | |
2156 | inst.error = "Register expected"; | |
2157 | return FAIL; | |
2158 | } | |
2159 | inst.instruction |= add | OFFSET_REG; | |
2160 | if (skip_past_comma (str) == SUCCESS) | |
2161 | return decode_shift (str, SHIFT_RESTRICT); | |
2162 | return SUCCESS; | |
2163 | } | |
2164 | } | |
2165 | ||
2166 | static void | |
2167 | do_ldst (str, flags) | |
2168 | char *str; | |
2169 | unsigned long flags; | |
2170 | { | |
2171 | int pre_inc = 0; | |
2172 | int conflict_reg; | |
2173 | int value; | |
2174 | ||
2175 | while (*str == ' ') | |
2176 | str++; | |
2177 | ||
2178 | if ((conflict_reg = reg_required_here (&str, 12)) == FAIL) | |
2179 | { | |
2180 | if (!inst.error) | |
2181 | inst.error = bad_args; | |
2182 | return; | |
2183 | } | |
2184 | ||
2185 | if (skip_past_comma (&str) == FAIL) | |
2186 | { | |
2187 | inst.error = "Address expected"; | |
2188 | return; | |
2189 | } | |
2190 | ||
2191 | if (*str == '[') | |
2192 | { | |
2193 | int reg; | |
2194 | ||
2195 | str++; | |
2196 | while (*str == ' ') | |
2197 | str++; | |
2198 | ||
2199 | if ((reg = reg_required_here (&str, 16)) == FAIL) | |
2200 | { | |
2201 | inst.error = "Register required"; | |
2202 | return; | |
2203 | } | |
2204 | ||
2205 | conflict_reg = (((conflict_reg == reg) | |
2206 | && (inst.instruction & 0x00100000)) | |
2207 | ? 1 : 0); | |
2208 | ||
2209 | while (*str == ' ') | |
2210 | str++; | |
2211 | ||
2212 | if (*str == ']') | |
2213 | { | |
2214 | str++; | |
2215 | if (skip_past_comma (&str) == SUCCESS) | |
2216 | { | |
2217 | /* [Rn],... (post inc) */ | |
2218 | if (ldst_extend (&str) == FAIL) | |
2219 | return; | |
2220 | if (conflict_reg) | |
2221 | as_warn ("destination register same as write-back base\n"); | |
2222 | } | |
2223 | else | |
2224 | { | |
2225 | /* [Rn] */ | |
2226 | flags |= INDEX_UP; | |
2227 | } | |
2228 | } | |
2229 | else | |
2230 | { | |
2231 | /* [Rn,...] */ | |
2232 | if (skip_past_comma (&str) == FAIL) | |
2233 | { | |
2234 | inst.error = "pre-indexed expression expected"; | |
2235 | return; | |
2236 | } | |
2237 | ||
2238 | pre_inc = 1; | |
2239 | if (ldst_extend (&str) == FAIL) | |
2240 | return; | |
2241 | ||
2242 | while (*str == ' ') | |
2243 | str++; | |
2244 | ||
2245 | if (*str++ != ']') | |
2246 | { | |
2247 | inst.error = "missing ]"; | |
2248 | return; | |
2249 | } | |
2250 | ||
2251 | while (*str == ' ') | |
2252 | str++; | |
2253 | ||
2254 | if (*str == '!') | |
2255 | { | |
2256 | if (conflict_reg) | |
2257 | as_warn ("destination register same as write-back base\n"); | |
2258 | str++; | |
2259 | inst.instruction |= WRITE_BACK; | |
2260 | } | |
2261 | } | |
2262 | } | |
2263 | else if (*str == '=') | |
2264 | { | |
2265 | /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */ | |
2266 | str++; | |
2267 | ||
2268 | while (*str == ' ') | |
2269 | str++; | |
2270 | ||
2271 | if (my_get_expression (&inst.reloc.exp, &str)) | |
2272 | return; | |
2273 | ||
2274 | if (inst.reloc.exp.X_op != O_constant | |
2275 | && inst.reloc.exp.X_op != O_symbol) | |
2276 | { | |
2277 | inst.error = "Constant expression expected"; | |
2278 | return; | |
2279 | } | |
2280 | ||
2281 | if (inst.reloc.exp.X_op == O_constant | |
2282 | && (value = validate_immediate(inst.reloc.exp.X_add_number)) != FAIL) | |
2283 | { | |
2284 | /* This can be done with a mov instruction */ | |
2285 | inst.instruction &= LITERAL_MASK; | |
2286 | inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT); | |
2287 | inst.instruction |= (flags & COND_MASK) | (value & 0xfff); | |
2288 | end_of_line(str); | |
2289 | return; | |
2290 | } | |
2291 | else | |
2292 | { | |
2293 | /* Insert into literal pool */ | |
2294 | if (add_to_lit_pool () == FAIL) | |
2295 | { | |
2296 | if (!inst.error) | |
2297 | inst.error = "literal pool insertion failed\n"; | |
2298 | return; | |
2299 | } | |
2300 | ||
2301 | /* Change the instruction exp to point to the pool */ | |
2302 | inst.reloc.type = BFD_RELOC_ARM_LITERAL; | |
2303 | inst.reloc.pc_rel = 1; | |
2304 | inst.instruction |= (REG_PC << 16); | |
2305 | pre_inc = 1; | |
2306 | } | |
2307 | } | |
2308 | else | |
2309 | { | |
2310 | if (my_get_expression (&inst.reloc.exp, &str)) | |
2311 | return; | |
2312 | ||
2313 | inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM; | |
2314 | inst.reloc.exp.X_add_number -= 8; /* PC rel adjust */ | |
2315 | inst.reloc.pc_rel = 1; | |
2316 | inst.instruction |= (REG_PC << 16); | |
2317 | pre_inc = 1; | |
2318 | } | |
2319 | ||
2320 | if (pre_inc && (flags & TRANS_BIT)) | |
2321 | inst.error = "Pre-increment instruction with translate"; | |
2322 | ||
2323 | inst.instruction |= flags | (pre_inc ? PRE_INDEX : 0); | |
2324 | end_of_line (str); | |
2325 | return; | |
2326 | } | |
2327 | ||
2328 | static void | |
2329 | do_ldmstm (str, flags) | |
2330 | char *str; | |
2331 | unsigned long flags; | |
2332 | { | |
2333 | int base_reg; | |
2334 | ||
2335 | while (*str == ' ') | |
2336 | str++; | |
2337 | ||
2338 | if ((base_reg = reg_required_here (&str, 16)) == FAIL) | |
2339 | { | |
2340 | if (!inst.error) | |
2341 | inst.error = bad_args; | |
2342 | return; | |
2343 | } | |
2344 | ||
2345 | if (base_reg == REG_PC) | |
2346 | { | |
2347 | inst.error = "r15 not allowed as base register"; | |
2348 | return; | |
2349 | } | |
2350 | ||
2351 | while (*str == ' ') | |
2352 | str++; | |
2353 | if (*str == '!') | |
2354 | { | |
2355 | flags |= WRITE_BACK; | |
2356 | str++; | |
2357 | } | |
2358 | ||
2359 | if (skip_past_comma (&str) == FAIL) | |
2360 | { | |
2361 | inst.error = bad_args; | |
2362 | return; | |
2363 | } | |
2364 | ||
2365 | /* We come back here if we get ranges concatenated by '+' or '|' */ | |
2366 | another_range: | |
2367 | if (*str == '{') | |
2368 | { | |
2369 | int in_range = 0; | |
2370 | int cur_reg = -1; | |
2371 | ||
2372 | str++; | |
2373 | do | |
2374 | { | |
2375 | int reg; | |
2376 | ||
2377 | while (*str == ' ') | |
2378 | str++; | |
2379 | ||
2380 | if ((reg = arm_reg_parse (&str)) == FAIL || !int_register (reg)) | |
2381 | { | |
2382 | inst.error = "Register expected"; | |
2383 | return; | |
2384 | } | |
2385 | ||
2386 | if (in_range) | |
2387 | { | |
2388 | int i; | |
2389 | ||
2390 | if (reg <= cur_reg) | |
2391 | { | |
2392 | inst.error = "Bad range in register list"; | |
2393 | return; | |
2394 | } | |
2395 | ||
2396 | for (i = cur_reg + 1; i < reg; i++) | |
2397 | { | |
2398 | if (flags & (1 << i)) | |
2399 | as_tsktsk | |
2400 | ("Warning: Duplicated register (r%d) in register list", | |
2401 | i); | |
2402 | else | |
2403 | flags |= 1 << i; | |
2404 | } | |
2405 | in_range = 0; | |
2406 | } | |
2407 | ||
2408 | if (flags & (1 << reg)) | |
2409 | as_tsktsk ("Warning: Duplicated register (r%d) in register list", | |
2410 | reg); | |
2411 | else if (reg <= cur_reg) | |
2412 | as_tsktsk ("Warning: Register range not in ascending order"); | |
2413 | ||
2414 | flags |= 1 << reg; | |
2415 | cur_reg = reg; | |
2416 | } while (skip_past_comma (&str) != FAIL | |
2417 | || (in_range = 1, *str++ == '-')); | |
2418 | str--; | |
2419 | while (*str == ' ') | |
2420 | str++; | |
2421 | ||
2422 | if (*str++ != '}') | |
2423 | { | |
2424 | inst.error = "Missing `}'"; | |
2425 | return; | |
2426 | } | |
2427 | } | |
2428 | else | |
2429 | { | |
2430 | expressionS expr; | |
2431 | ||
2432 | if (my_get_expression (&expr, &str)) | |
2433 | return; | |
2434 | ||
2435 | if (expr.X_op == O_constant) | |
2436 | { | |
2437 | if (expr.X_add_number | |
2438 | != (expr.X_add_number & 0x0000ffff)) | |
2439 | { | |
2440 | inst.error = "invalid register mask"; | |
2441 | return; | |
2442 | } | |
2443 | ||
2444 | if ((flags & expr.X_add_number) != 0) | |
2445 | { | |
2446 | int regno = flags & expr.X_add_number; | |
2447 | ||
2448 | regno &= -regno; | |
2449 | regno = (1 << regno) - 1; | |
2450 | as_tsktsk ("Warning: Duplicated register (r%d) in register list", | |
2451 | regno); | |
2452 | } | |
2453 | ||
2454 | flags |= expr.X_add_number; | |
2455 | } | |
2456 | else | |
2457 | { | |
2458 | if (inst.reloc.type != 0) | |
2459 | { | |
2460 | inst.error = "expression too complex"; | |
2461 | return; | |
2462 | } | |
2463 | ||
2464 | memcpy (&inst.reloc.exp, &expr, sizeof (expressionS)); | |
2465 | inst.reloc.type = BFD_RELOC_ARM_MULTI; | |
2466 | inst.reloc.pc_rel = 0; | |
2467 | } | |
2468 | } | |
2469 | ||
2470 | while (*str == ' ') | |
2471 | str++; | |
2472 | ||
2473 | if (*str == '|' || *str == '+') | |
2474 | { | |
2475 | str++; | |
2476 | goto another_range; | |
2477 | } | |
2478 | ||
2479 | if (*str == '^') | |
2480 | { | |
2481 | str++; | |
2482 | flags |= MULTI_SET_PSR; | |
2483 | } | |
2484 | inst.instruction |= flags; | |
2485 | end_of_line (str); | |
2486 | return; | |
2487 | } | |
2488 | ||
2489 | static void | |
2490 | do_swi (str, flags) | |
2491 | char *str; | |
2492 | unsigned long flags; | |
2493 | { | |
2494 | /* Allow optional leading '#'. */ | |
2495 | while (*str == ' ') | |
2496 | str++; | |
2497 | if (*str == '#') | |
2498 | str++; | |
2499 | ||
2500 | if (my_get_expression (&inst.reloc.exp, &str)) | |
2501 | return; | |
2502 | ||
2503 | inst.reloc.type = BFD_RELOC_ARM_SWI; | |
2504 | inst.reloc.pc_rel = 0; | |
2505 | inst.instruction |= flags; | |
2506 | end_of_line (str); | |
2507 | return; | |
2508 | } | |
2509 | ||
2510 | static void | |
2511 | do_swap (str, flags) | |
2512 | char *str; | |
2513 | unsigned long flags; | |
2514 | { | |
2515 | int reg; | |
2516 | ||
2517 | while (*str == ' ') | |
2518 | str++; | |
2519 | ||
2520 | if ((reg = reg_required_here (&str, 12)) == FAIL) | |
2521 | return; | |
2522 | ||
2523 | if (reg == REG_PC) | |
2524 | { | |
2525 | inst.error = "r15 not allowed in swap"; | |
2526 | return; | |
2527 | } | |
2528 | ||
2529 | if (skip_past_comma (&str) == FAIL | |
2530 | || (reg = reg_required_here (&str, 0)) == FAIL) | |
2531 | { | |
2532 | if (!inst.error) | |
2533 | inst.error = bad_args; | |
2534 | return; | |
2535 | } | |
2536 | ||
2537 | if (reg == REG_PC) | |
2538 | { | |
2539 | inst.error = "r15 not allowed in swap"; | |
2540 | return; | |
2541 | } | |
2542 | ||
2543 | if (skip_past_comma (&str) == FAIL | |
2544 | || *str++ != '[') | |
2545 | { | |
2546 | inst.error = bad_args; | |
2547 | return; | |
2548 | } | |
2549 | ||
2550 | while (*str == ' ') | |
2551 | str++; | |
2552 | ||
2553 | if ((reg = reg_required_here (&str, 16)) == FAIL) | |
2554 | return; | |
2555 | ||
2556 | if (reg == REG_PC) | |
2557 | { | |
2558 | inst.error = bad_pc; | |
2559 | return; | |
2560 | } | |
2561 | ||
2562 | while (*str == ' ') | |
2563 | str++; | |
2564 | ||
2565 | if (*str++ != ']') | |
2566 | { | |
2567 | inst.error = "missing ]"; | |
2568 | return; | |
2569 | } | |
2570 | ||
2571 | inst.instruction |= flags; | |
2572 | end_of_line (str); | |
2573 | return; | |
2574 | } | |
2575 | ||
2576 | static void | |
2577 | do_branch (str, flags) | |
2578 | char *str; | |
2579 | unsigned long flags; | |
2580 | { | |
2581 | if (my_get_expression (&inst.reloc.exp, &str)) | |
2582 | return; | |
2583 | inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; | |
2584 | inst.reloc.pc_rel = 1; | |
2585 | inst.instruction |= flags | 0x00fffffe; /* PC-rel adjust */ | |
2586 | end_of_line (str); | |
2587 | return; | |
2588 | } | |
2589 | ||
2590 | static void | |
2591 | do_cdp (str, flags) | |
2592 | char *str; | |
2593 | unsigned long flags; | |
2594 | { | |
2595 | /* Co-processor data operation. | |
2596 | Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */ | |
2597 | while (*str == ' ') | |
2598 | str++; | |
2599 | ||
2600 | if (co_proc_number (&str) == FAIL) | |
2601 | { | |
2602 | if (!inst.error) | |
2603 | inst.error = bad_args; | |
2604 | return; | |
2605 | } | |
2606 | ||
2607 | if (skip_past_comma (&str) == FAIL | |
2608 | || cp_opc_expr (&str, 20,4) == FAIL) | |
2609 | { | |
2610 | if (!inst.error) | |
2611 | inst.error = bad_args; | |
2612 | return; | |
2613 | } | |
2614 | ||
2615 | if (skip_past_comma (&str) == FAIL | |
2616 | || cp_reg_required_here (&str, 12) == FAIL) | |
2617 | { | |
2618 | if (!inst.error) | |
2619 | inst.error = bad_args; | |
2620 | return; | |
2621 | } | |
2622 | ||
2623 | if (skip_past_comma (&str) == FAIL | |
2624 | || cp_reg_required_here (&str, 16) == FAIL) | |
2625 | { | |
2626 | if (!inst.error) | |
2627 | inst.error = bad_args; | |
2628 | return; | |
2629 | } | |
2630 | ||
2631 | if (skip_past_comma (&str) == FAIL | |
2632 | || cp_reg_required_here (&str, 0) == FAIL) | |
2633 | { | |
2634 | if (!inst.error) | |
2635 | inst.error = bad_args; | |
2636 | return; | |
2637 | } | |
2638 | ||
2639 | if (skip_past_comma (&str) == SUCCESS) | |
2640 | { | |
2641 | if (cp_opc_expr (&str, 5, 3) == FAIL) | |
2642 | { | |
2643 | if (!inst.error) | |
2644 | inst.error = bad_args; | |
2645 | return; | |
2646 | } | |
2647 | } | |
2648 | ||
2649 | end_of_line (str); | |
2650 | return; | |
2651 | } | |
2652 | ||
2653 | static void | |
2654 | do_lstc (str, flags) | |
2655 | char *str; | |
2656 | unsigned long flags; | |
2657 | { | |
2658 | /* Co-processor register load/store. | |
2659 | Format: <LDC|STC{cond}[L] CP#,CRd,<address> */ | |
2660 | ||
2661 | while (*str == ' ') | |
2662 | str++; | |
2663 | ||
2664 | if (co_proc_number (&str) == FAIL) | |
2665 | { | |
2666 | if (!inst.error) | |
2667 | inst.error = bad_args; | |
2668 | return; | |
2669 | } | |
2670 | ||
2671 | if (skip_past_comma (&str) == FAIL | |
2672 | || cp_reg_required_here (&str, 12) == FAIL) | |
2673 | { | |
2674 | if (!inst.error) | |
2675 | inst.error = bad_args; | |
2676 | return; | |
2677 | } | |
2678 | ||
2679 | if (skip_past_comma (&str) == FAIL | |
2680 | || cp_address_required_here (&str) == FAIL) | |
2681 | { | |
2682 | if (! inst.error) | |
2683 | inst.error = bad_args; | |
2684 | return; | |
2685 | } | |
2686 | ||
2687 | inst.instruction |= flags; | |
2688 | end_of_line (str); | |
2689 | return; | |
2690 | } | |
2691 | ||
2692 | static void | |
2693 | do_co_reg (str, flags) | |
2694 | char *str; | |
2695 | unsigned long flags; | |
2696 | { | |
2697 | /* Co-processor register transfer. | |
2698 | Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */ | |
2699 | ||
2700 | while (*str == ' ') | |
2701 | str++; | |
2702 | ||
2703 | if (co_proc_number (&str) == FAIL) | |
2704 | { | |
2705 | if (!inst.error) | |
2706 | inst.error = bad_args; | |
2707 | return; | |
2708 | } | |
2709 | ||
2710 | if (skip_past_comma (&str) == FAIL | |
2711 | || cp_opc_expr (&str, 21, 3) == FAIL) | |
2712 | { | |
2713 | if (!inst.error) | |
2714 | inst.error = bad_args; | |
2715 | return; | |
2716 | } | |
2717 | ||
2718 | if (skip_past_comma (&str) == FAIL | |
2719 | || reg_required_here (&str, 12) == FAIL) | |
2720 | { | |
2721 | if (!inst.error) | |
2722 | inst.error = bad_args; | |
2723 | return; | |
2724 | } | |
2725 | ||
2726 | if (skip_past_comma (&str) == FAIL | |
2727 | || cp_reg_required_here (&str, 16) == FAIL) | |
2728 | { | |
2729 | if (!inst.error) | |
2730 | inst.error = bad_args; | |
2731 | return; | |
2732 | } | |
2733 | ||
2734 | if (skip_past_comma (&str) == FAIL | |
2735 | || cp_reg_required_here (&str, 0) == FAIL) | |
2736 | { | |
2737 | if (!inst.error) | |
2738 | inst.error = bad_args; | |
2739 | return; | |
2740 | } | |
2741 | ||
2742 | if (skip_past_comma (&str) == SUCCESS) | |
2743 | { | |
2744 | if (cp_opc_expr (&str, 5, 3) == FAIL) | |
2745 | { | |
2746 | if (!inst.error) | |
2747 | inst.error = bad_args; | |
2748 | return; | |
2749 | } | |
2750 | } | |
2751 | ||
2752 | end_of_line (str); | |
2753 | return; | |
2754 | } | |
2755 | ||
2756 | static void | |
2757 | do_fp_ctrl (str, flags) | |
2758 | char *str; | |
2759 | unsigned long flags; | |
2760 | { | |
2761 | /* FP control registers. | |
2762 | Format: <WFS|RFS|WFC|RFC>{cond} Rn */ | |
2763 | ||
2764 | while (*str == ' ') | |
2765 | str++; | |
2766 | ||
2767 | if (reg_required_here (&str, 12) == FAIL) | |
2768 | { | |
2769 | if (!inst.error) | |
2770 | inst.error = bad_args; | |
2771 | return; | |
2772 | } | |
2773 | ||
2774 | end_of_line (str); | |
2775 | return; | |
2776 | } | |
2777 | ||
2778 | static void | |
2779 | do_fp_ldst (str, flags) | |
2780 | char *str; | |
2781 | unsigned long flags; | |
2782 | { | |
2783 | while (*str == ' ') | |
2784 | str++; | |
2785 | ||
2786 | switch (inst.suffix) | |
2787 | { | |
2788 | case SUFF_S: | |
2789 | break; | |
2790 | case SUFF_D: | |
2791 | inst.instruction |= CP_T_X; | |
2792 | break; | |
2793 | case SUFF_E: | |
2794 | inst.instruction |= CP_T_Y; | |
2795 | break; | |
2796 | case SUFF_P: | |
2797 | inst.instruction |= CP_T_X | CP_T_Y; | |
2798 | break; | |
2799 | default: | |
2800 | abort (); | |
2801 | } | |
2802 | ||
2803 | if (fp_reg_required_here (&str, 12) == FAIL) | |
2804 | { | |
2805 | if (!inst.error) | |
2806 | inst.error = bad_args; | |
2807 | return; | |
2808 | } | |
2809 | ||
2810 | if (skip_past_comma (&str) == FAIL | |
2811 | || cp_address_required_here (&str) == FAIL) | |
2812 | { | |
2813 | if (!inst.error) | |
2814 | inst.error = bad_args; | |
2815 | return; | |
2816 | } | |
2817 | ||
2818 | end_of_line (str); | |
2819 | } | |
2820 | ||
2821 | static void | |
2822 | do_fp_ldmstm (str, flags) | |
2823 | char *str; | |
2824 | unsigned long flags; | |
2825 | { | |
2826 | int num_regs; | |
2827 | ||
2828 | while (*str == ' ') | |
2829 | str++; | |
2830 | ||
2831 | if (fp_reg_required_here (&str, 12) == FAIL) | |
2832 | { | |
2833 | if (! inst.error) | |
2834 | inst.error = bad_args; | |
2835 | return; | |
2836 | } | |
2837 | ||
2838 | /* Get Number of registers to transfer */ | |
2839 | if (skip_past_comma (&str) == FAIL | |
2840 | || my_get_expression (&inst.reloc.exp, &str)) | |
2841 | { | |
2842 | if (! inst.error) | |
2843 | inst.error = "constant expression expected"; | |
2844 | return; | |
2845 | } | |
2846 | ||
2847 | if (inst.reloc.exp.X_op != O_constant) | |
2848 | { | |
2849 | inst.error = "Constant value required for number of registers"; | |
2850 | return; | |
2851 | } | |
2852 | ||
2853 | num_regs = inst.reloc.exp.X_add_number; | |
2854 | ||
2855 | if (num_regs < 1 || num_regs > 4) | |
2856 | { | |
2857 | inst.error = "number of registers must be in the range [1:4]"; | |
2858 | return; | |
2859 | } | |
2860 | ||
2861 | switch (num_regs) | |
2862 | { | |
2863 | case 1: | |
2864 | inst.instruction |= CP_T_X; | |
2865 | break; | |
2866 | case 2: | |
2867 | inst.instruction |= CP_T_Y; | |
2868 | break; | |
2869 | case 3: | |
2870 | inst.instruction |= CP_T_Y | CP_T_X; | |
2871 | break; | |
2872 | case 4: | |
2873 | break; | |
2874 | default: | |
2875 | abort (); | |
2876 | } | |
2877 | ||
2878 | if (flags) | |
2879 | { | |
2880 | int reg; | |
2881 | int write_back; | |
2882 | int offset; | |
2883 | ||
2884 | /* The instruction specified "ea" or "fd", so we can only accept | |
2885 | [Rn]{!}. The instruction does not really support stacking or | |
2886 | unstacking, so we have to emulate these by setting appropriate | |
2887 | bits and offsets. */ | |
2888 | if (skip_past_comma (&str) == FAIL | |
2889 | || *str != '[') | |
2890 | { | |
2891 | if (! inst.error) | |
2892 | inst.error = bad_args; | |
2893 | return; | |
2894 | } | |
2895 | ||
2896 | str++; | |
2897 | while (*str == ' ') | |
2898 | str++; | |
2899 | ||
2900 | if ((reg = reg_required_here (&str, 16)) == FAIL) | |
2901 | { | |
2902 | inst.error = "Register required"; | |
2903 | return; | |
2904 | } | |
2905 | ||
2906 | while (*str == ' ') | |
2907 | str++; | |
2908 | ||
2909 | if (*str != ']') | |
2910 | { | |
2911 | inst.error = bad_args; | |
2912 | return; | |
2913 | } | |
2914 | ||
2915 | str++; | |
2916 | if (*str == '!') | |
2917 | { | |
2918 | write_back = 1; | |
2919 | str++; | |
2920 | if (reg == REG_PC) | |
2921 | { | |
2922 | inst.error = "R15 not allowed as base register with write-back"; | |
2923 | return; | |
2924 | } | |
2925 | } | |
2926 | else | |
2927 | write_back = 0; | |
2928 | ||
2929 | if (flags & CP_T_Pre) | |
2930 | { | |
2931 | /* Pre-decrement */ | |
2932 | offset = 3 * num_regs; | |
2933 | if (write_back) | |
2934 | flags |= CP_T_WB; | |
2935 | } | |
2936 | else | |
2937 | { | |
2938 | /* Post-increment */ | |
2939 | if (write_back) | |
2940 | { | |
2941 | flags |= CP_T_WB; | |
2942 | offset = 3 * num_regs; | |
2943 | } | |
2944 | else | |
2945 | { | |
2946 | /* No write-back, so convert this into a standard pre-increment | |
2947 | instruction -- aesthetically more pleasing. */ | |
2948 | flags = CP_T_Pre | CP_T_UD; | |
2949 | offset = 0; | |
2950 | } | |
2951 | } | |
2952 | ||
2953 | inst.instruction |= flags | offset; | |
2954 | } | |
2955 | else if (skip_past_comma (&str) == FAIL | |
2956 | || cp_address_required_here (&str) == FAIL) | |
2957 | { | |
2958 | if (! inst.error) | |
2959 | inst.error = bad_args; | |
2960 | return; | |
2961 | } | |
2962 | ||
2963 | end_of_line (str); | |
2964 | } | |
2965 | ||
2966 | static void | |
2967 | do_fp_dyadic (str, flags) | |
2968 | char *str; | |
2969 | unsigned long flags; | |
2970 | { | |
2971 | while (*str == ' ') | |
2972 | str++; | |
2973 | ||
2974 | switch (inst.suffix) | |
2975 | { | |
2976 | case SUFF_S: | |
2977 | break; | |
2978 | case SUFF_D: | |
2979 | inst.instruction |= 0x00000080; | |
2980 | break; | |
2981 | case SUFF_E: | |
2982 | inst.instruction |= 0x00080000; | |
2983 | break; | |
2984 | default: | |
2985 | abort (); | |
2986 | } | |
2987 | ||
2988 | if (fp_reg_required_here (&str, 12) == FAIL) | |
2989 | { | |
2990 | if (! inst.error) | |
2991 | inst.error = bad_args; | |
2992 | return; | |
2993 | } | |
2994 | ||
2995 | if (skip_past_comma (&str) == FAIL | |
2996 | || fp_reg_required_here (&str, 16) == FAIL) | |
2997 | { | |
2998 | if (! inst.error) | |
2999 | inst.error = bad_args; | |
3000 | return; | |
3001 | } | |
3002 | ||
3003 | if (skip_past_comma (&str) == FAIL | |
3004 | || fp_op2 (&str) == FAIL) | |
3005 | { | |
3006 | if (! inst.error) | |
3007 | inst.error = bad_args; | |
3008 | return; | |
3009 | } | |
3010 | ||
3011 | inst.instruction |= flags; | |
3012 | end_of_line (str); | |
3013 | return; | |
3014 | } | |
3015 | ||
3016 | static void | |
3017 | do_fp_monadic (str, flags) | |
3018 | char *str; | |
3019 | unsigned long flags; | |
3020 | { | |
3021 | while (*str == ' ') | |
3022 | str++; | |
3023 | ||
3024 | switch (inst.suffix) | |
3025 | { | |
3026 | case SUFF_S: | |
3027 | break; | |
3028 | case SUFF_D: | |
3029 | inst.instruction |= 0x00000080; | |
3030 | break; | |
3031 | case SUFF_E: | |
3032 | inst.instruction |= 0x00080000; | |
3033 | break; | |
3034 | default: | |
3035 | abort (); | |
3036 | } | |
3037 | ||
3038 | if (fp_reg_required_here (&str, 12) == FAIL) | |
3039 | { | |
3040 | if (! inst.error) | |
3041 | inst.error = bad_args; | |
3042 | return; | |
3043 | } | |
3044 | ||
3045 | if (skip_past_comma (&str) == FAIL | |
3046 | || fp_op2 (&str) == FAIL) | |
3047 | { | |
3048 | if (! inst.error) | |
3049 | inst.error = bad_args; | |
3050 | return; | |
3051 | } | |
3052 | ||
3053 | inst.instruction |= flags; | |
3054 | end_of_line (str); | |
3055 | return; | |
3056 | } | |
3057 | ||
3058 | static void | |
3059 | do_fp_cmp (str, flags) | |
3060 | char *str; | |
3061 | unsigned long flags; | |
3062 | { | |
3063 | while (*str == ' ') | |
3064 | str++; | |
3065 | ||
3066 | if (fp_reg_required_here (&str, 16) == FAIL) | |
3067 | { | |
3068 | if (! inst.error) | |
3069 | inst.error = bad_args; | |
3070 | return; | |
3071 | } | |
3072 | ||
3073 | if (skip_past_comma (&str) == FAIL | |
3074 | || fp_op2 (&str) == FAIL) | |
3075 | { | |
3076 | if (! inst.error) | |
3077 | inst.error = bad_args; | |
3078 | return; | |
3079 | } | |
3080 | ||
3081 | inst.instruction |= flags; | |
3082 | end_of_line (str); | |
3083 | return; | |
3084 | } | |
3085 | ||
3086 | static void | |
3087 | do_fp_from_reg (str, flags) | |
3088 | char *str; | |
3089 | unsigned long flags; | |
3090 | { | |
3091 | while (*str == ' ') | |
3092 | str++; | |
3093 | ||
3094 | switch (inst.suffix) | |
3095 | { | |
3096 | case SUFF_S: | |
3097 | break; | |
3098 | case SUFF_D: | |
3099 | inst.instruction |= 0x00000080; | |
3100 | break; | |
3101 | case SUFF_E: | |
3102 | inst.instruction |= 0x00080000; | |
3103 | break; | |
3104 | default: | |
3105 | abort (); | |
3106 | } | |
3107 | ||
3108 | if (fp_reg_required_here (&str, 16) == FAIL) | |
3109 | { | |
3110 | if (! inst.error) | |
3111 | inst.error = bad_args; | |
3112 | return; | |
3113 | } | |
3114 | ||
3115 | if (skip_past_comma (&str) == FAIL | |
3116 | || reg_required_here (&str, 12) == FAIL) | |
3117 | { | |
3118 | if (! inst.error) | |
3119 | inst.error = bad_args; | |
3120 | return; | |
3121 | } | |
3122 | ||
3123 | inst.instruction |= flags; | |
3124 | end_of_line (str); | |
3125 | return; | |
3126 | } | |
3127 | ||
3128 | static void | |
3129 | do_fp_to_reg (str, flags) | |
3130 | char *str; | |
3131 | unsigned long flags; | |
3132 | { | |
3133 | while (*str == ' ') | |
3134 | str++; | |
3135 | ||
3136 | if (reg_required_here (&str, 12) == FAIL) | |
3137 | { | |
3138 | if (! inst.error) | |
3139 | inst.error = bad_args; | |
3140 | return; | |
3141 | } | |
3142 | ||
3143 | if (skip_past_comma (&str) == FAIL | |
3144 | || fp_reg_required_here (&str, 0) == FAIL) | |
3145 | { | |
3146 | if (! inst.error) | |
3147 | inst.error = bad_args; | |
3148 | return; | |
3149 | } | |
3150 | ||
3151 | inst.instruction |= flags; | |
3152 | end_of_line (str); | |
3153 | return; | |
3154 | } | |
3155 | ||
3156 | static void | |
3157 | insert_reg (entry) | |
3158 | int entry; | |
3159 | { | |
3160 | int len = strlen (reg_table[entry].name) + 2; | |
3161 | char *buf = (char *) xmalloc (len); | |
3162 | char *buf2 = (char *) xmalloc (len); | |
3163 | int i = 0; | |
3164 | ||
3165 | #ifdef REGISTER_PREFIX | |
3166 | buf[i++] = REGISTER_PREFIX; | |
3167 | #endif | |
3168 | ||
3169 | strcpy (buf + i, reg_table[entry].name); | |
3170 | ||
3171 | for (i = 0; buf[i]; i++) | |
3172 | buf2[i] = islower (buf[i]) ? toupper (buf[i]) : buf[i]; | |
3173 | ||
3174 | buf2[i] = '\0'; | |
3175 | ||
3176 | hash_insert (arm_reg_hsh, buf, (PTR) ®_table[entry]); | |
3177 | hash_insert (arm_reg_hsh, buf2, (PTR) ®_table[entry]); | |
3178 | } | |
3179 | ||
3180 | static void | |
3181 | insert_reg_alias (str, regnum) | |
3182 | char *str; | |
3183 | int regnum; | |
3184 | { | |
3185 | struct reg_entry *new = | |
3186 | (struct reg_entry *)xmalloc (sizeof (struct reg_entry)); | |
3187 | char *name = xmalloc (strlen (str) + 1); | |
3188 | strcpy (name, str); | |
3189 | ||
3190 | new->name = name; | |
3191 | new->number = regnum; | |
3192 | ||
3193 | hash_insert (arm_reg_hsh, name, (PTR) new); | |
3194 | } | |
3195 | ||
3196 | static void | |
3197 | set_constant_flonums () | |
3198 | { | |
3199 | int i; | |
3200 | ||
3201 | for (i = 0; i < NUM_FLOAT_VALS; i++) | |
3202 | if (atof_ieee ((char *)fp_const[i], 'x', fp_values[i]) == NULL) | |
3203 | abort (); | |
3204 | } | |
3205 | ||
3206 | void | |
3207 | md_begin () | |
3208 | { | |
3209 | int i; | |
3210 | ||
3211 | if ((arm_ops_hsh = hash_new ()) == NULL | |
3212 | || (arm_cond_hsh = hash_new ()) == NULL | |
3213 | || (arm_shift_hsh = hash_new ()) == NULL | |
3214 | || (arm_reg_hsh = hash_new ()) == NULL | |
3215 | || (arm_psr_hsh = hash_new ()) == NULL) | |
3216 | as_fatal ("Virtual memory exhausted"); | |
3217 | ||
3218 | for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++) | |
3219 | hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i)); | |
3220 | for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++) | |
3221 | hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i)); | |
3222 | for (i = 0; i < sizeof (shift) / sizeof (struct asm_shift); i++) | |
3223 | hash_insert (arm_shift_hsh, shift[i].template, (PTR) (shift + i)); | |
3224 | for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++) | |
3225 | hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i)); | |
3226 | ||
3227 | for (i = 0; reg_table[i].name; i++) | |
3228 | insert_reg (i); | |
3229 | ||
3230 | set_constant_flonums (); | |
3231 | } | |
3232 | ||
3233 | /* This funciton is called once, before the assembler exits. It is | |
3234 | supposed to do any final cleanup for this part of the assembler. | |
3235 | */ | |
3236 | void | |
3237 | md_end () | |
3238 | { | |
3239 | } | |
3240 | ||
3241 | /* Turn an integer of n bytes (in val) into a stream of bytes appropriate | |
3242 | for use in the a.out file, and stores them in the array pointed to by buf. | |
3243 | This knows about the endian-ness of the target machine and does | |
3244 | THE RIGHT THING, whatever it is. Possible values for n are 1 (byte) | |
3245 | 2 (short) and 4 (long) Floating numbers are put out as a series of | |
3246 | LITTLENUMS (shorts, here at least) | |
3247 | */ | |
3248 | void | |
3249 | md_number_to_chars (buf, val, n) | |
3250 | char *buf; | |
3251 | valueT val; | |
3252 | int n; | |
3253 | { | |
3254 | if (target_big_endian) | |
3255 | number_to_chars_bigendian (buf, val, n); | |
3256 | else | |
3257 | number_to_chars_littleendian (buf, val, n); | |
3258 | } | |
3259 | ||
3260 | static valueT | |
3261 | md_chars_to_number (buf, n) | |
3262 | char *buf; | |
3263 | int n; | |
3264 | { | |
3265 | valueT result = 0; | |
3266 | unsigned char *where = (unsigned char *) buf; | |
3267 | ||
3268 | if (target_big_endian) | |
3269 | { | |
3270 | while (n--) | |
3271 | { | |
3272 | result <<= 8; | |
3273 | result |= (*where++ & 255); | |
3274 | } | |
3275 | } | |
3276 | else | |
3277 | { | |
3278 | while (n--) | |
3279 | { | |
3280 | result <<= 8; | |
3281 | result |= (where[n] & 255); | |
3282 | } | |
3283 | } | |
3284 | ||
3285 | return result; | |
3286 | } | |
3287 | ||
3288 | /* | |
3289 | This is identical to the md_atof in m68k.c. I think this is right, | |
3290 | but I'm not sure. | |
3291 | ||
3292 | Turn a string in input_line_pointer into a floating point constant of type | |
3293 | type, and store the appropriate bytes in *litP. The number of LITTLENUMS | |
3294 | emitted is stored in *sizeP . An error message is returned, or NULL on OK. | |
3295 | */ | |
3296 | char * | |
3297 | md_atof (type, litP, sizeP) | |
3298 | char type; | |
3299 | char *litP; | |
3300 | int *sizeP; | |
3301 | { | |
3302 | int prec; | |
3303 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
3304 | LITTLENUM_TYPE *wordP; | |
3305 | char *t; | |
3306 | char *atof_ieee (); | |
3307 | ||
3308 | switch (type) | |
3309 | { | |
3310 | ||
3311 | case 'f': | |
3312 | case 'F': | |
3313 | case 's': | |
3314 | case 'S': | |
3315 | prec = 2; | |
3316 | break; | |
3317 | ||
3318 | case 'd': | |
3319 | case 'D': | |
3320 | case 'r': | |
3321 | case 'R': | |
3322 | prec = 4; | |
3323 | break; | |
3324 | ||
3325 | case 'x': | |
3326 | case 'X': | |
3327 | prec = 6; | |
3328 | break; | |
3329 | ||
3330 | case 'p': | |
3331 | case 'P': | |
3332 | prec = 6; | |
3333 | break; | |
3334 | ||
3335 | default: | |
3336 | *sizeP = 0; | |
3337 | return "Bad call to MD_ATOF()"; | |
3338 | } | |
3339 | t = atof_ieee (input_line_pointer, type, words); | |
3340 | if (t) | |
3341 | input_line_pointer = t; | |
3342 | *sizeP = prec * sizeof (LITTLENUM_TYPE); | |
3343 | for (wordP = words; prec--;) | |
3344 | { | |
3345 | fprintf (stderr, "%02x 02x ", ((*wordP) >> 8) & 255, (*wordP) & 255); | |
3346 | md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); | |
3347 | litP += sizeof (LITTLENUM_TYPE); | |
3348 | } | |
3349 | fprintf (stderr, "\n"); | |
3350 | return 0; | |
3351 | } | |
3352 | ||
3353 | /* We have already put the pipeline compensation in the instruction */ | |
3354 | ||
3355 | long | |
3356 | md_pcrel_from (fixP) | |
3357 | fixS *fixP; | |
3358 | { | |
3359 | if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section | |
3360 | && fixP->fx_subsy == NULL) | |
3361 | return 0; /* HACK */ | |
3362 | ||
3363 | return fixP->fx_where + fixP->fx_frag->fr_address; | |
3364 | } | |
3365 | ||
3366 | /* Round up a section size to the appropriate boundary. */ | |
3367 | valueT | |
3368 | md_section_align (segment, size) | |
3369 | segT segment; | |
3370 | valueT size; | |
3371 | { | |
3372 | /* Round all sects to multiple of 4 */ | |
3373 | return (size + 3) & ~3; | |
3374 | } | |
3375 | ||
3376 | /* We have no need to default values of symbols. */ | |
3377 | ||
3378 | /* ARGSUSED */ | |
3379 | symbolS * | |
3380 | md_undefined_symbol (name) | |
3381 | char *name; | |
3382 | { | |
3383 | return 0; | |
3384 | } | |
3385 | ||
3386 | /* arm_reg_parse () := if it looks like a register, return its token and | |
3387 | advance the pointer. */ | |
3388 | ||
3389 | static int | |
3390 | arm_reg_parse (ccp) | |
3391 | register char **ccp; | |
3392 | { | |
3393 | char *start = *ccp; | |
3394 | char c; | |
3395 | char *p; | |
3396 | struct reg_entry *reg; | |
3397 | ||
3398 | #ifdef REGISTER_PREFIX | |
3399 | if (*start != REGISTER_PREFIX) | |
3400 | return FAIL; | |
3401 | p = start + 1; | |
3402 | #else | |
3403 | p = start; | |
3404 | #ifdef OPTIONAL_REGISTER_PREFIX | |
3405 | if (*p == OPTIONAL_REGISTER_PREFIX) | |
3406 | p++, start++; | |
3407 | #endif | |
3408 | #endif | |
3409 | if (!isalpha (*p) || !is_name_beginner (*p)) | |
3410 | return FAIL; | |
3411 | ||
3412 | c = *p++; | |
3413 | while (isalpha (c) || isdigit (c) || c == '_') | |
3414 | c = *p++; | |
3415 | ||
3416 | *--p = 0; | |
3417 | reg = (struct reg_entry *) hash_find (arm_reg_hsh, start); | |
3418 | *p = c; | |
3419 | ||
3420 | if (reg) | |
3421 | { | |
3422 | *ccp = p; | |
3423 | return reg->number; | |
3424 | } | |
3425 | ||
3426 | return FAIL; | |
3427 | } | |
3428 | ||
3429 | static int | |
3430 | arm_psr_parse (ccp) | |
3431 | register char **ccp; | |
3432 | { | |
3433 | char *start = *ccp; | |
3434 | char c, *p; | |
3435 | CONST struct asm_psr *psr; | |
3436 | ||
3437 | p = start; | |
3438 | c = *p++; | |
3439 | while (isalpha (c) || c == '_') | |
3440 | c = *p++; | |
3441 | ||
3442 | *--p = 0; | |
3443 | psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start); | |
3444 | *p = c; | |
3445 | ||
3446 | if (psr) | |
3447 | { | |
3448 | *ccp = p; | |
3449 | return psr->number; | |
3450 | } | |
3451 | ||
3452 | return FAIL; | |
3453 | } | |
3454 | ||
3455 | int | |
3456 | md_apply_fix (fixP, val) | |
3457 | fixS *fixP; | |
3458 | valueT *val; | |
3459 | { | |
3460 | offsetT value = *val; | |
3461 | offsetT newval, temp; | |
3462 | int sign; | |
3463 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; | |
3464 | ||
3465 | assert (fixP->fx_r_type < BFD_RELOC_UNUSED); | |
3466 | ||
3467 | fixP->fx_addnumber = value; /* Remember value for emit_reloc */ | |
3468 | ||
3469 | /* Note whether this will delete the relocation. */ | |
3470 | if (fixP->fx_addsy == 0 && !fixP->fx_pcrel) | |
3471 | fixP->fx_done = 1; | |
3472 | ||
3473 | switch (fixP->fx_r_type) | |
3474 | { | |
3475 | case BFD_RELOC_ARM_IMMEDIATE: | |
3476 | newval = validate_immediate (value); | |
3477 | temp = md_chars_to_number (buf, INSN_SIZE); | |
3478 | ||
3479 | /* If the instruction will fail, see if we can fix things up by | |
3480 | changing the opcode. */ | |
3481 | if (newval == FAIL | |
3482 | && (newval = negate_data_op (&temp, value)) == FAIL) | |
3483 | { | |
3484 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
3485 | "invalid constant after fixup\n"); | |
3486 | break; | |
3487 | } | |
3488 | ||
3489 | newval |= (temp & 0xfffff000); | |
3490 | md_number_to_chars (buf, newval, INSN_SIZE); | |
3491 | break; | |
3492 | ||
3493 | case BFD_RELOC_ARM_OFFSET_IMM: | |
3494 | sign = value >= 0; | |
3495 | value = validate_offset_imm (value); /* Should be OK ... but .... */ | |
3496 | if (value < 0) | |
3497 | value = -value; | |
3498 | ||
3499 | newval = md_chars_to_number (buf, INSN_SIZE); | |
3500 | newval &= 0xff7ff000; | |
3501 | newval |= value | (sign ? 0x00800000 : 0); | |
3502 | md_number_to_chars (buf, newval, INSN_SIZE); | |
3503 | break; | |
3504 | ||
3505 | case BFD_RELOC_ARM_LITERAL: | |
3506 | sign = value >= 0; | |
3507 | if (value < 0) | |
3508 | value = -value; | |
3509 | ||
3510 | if ((value = validate_immediate (value)) == FAIL) | |
3511 | { | |
3512 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
3513 | "invalid literal constant: pool needs to be closer\n"); | |
3514 | break; | |
3515 | } | |
3516 | ||
3517 | newval = md_chars_to_number (buf, INSN_SIZE); | |
3518 | newval &= 0xff7ff000; | |
3519 | newval |= value | (sign ? 0x00800000 : 0); | |
3520 | md_number_to_chars (buf, newval, INSN_SIZE); | |
3521 | break; | |
3522 | ||
3523 | case BFD_RELOC_ARM_SHIFT_IMM: | |
3524 | newval = md_chars_to_number (buf, INSN_SIZE); | |
3525 | if (((unsigned long) value) > 32 | |
3526 | || (value == 32 | |
3527 | && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60))) | |
3528 | { | |
3529 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
3530 | "shift expression is too large"); | |
3531 | break; | |
3532 | } | |
3533 | ||
3534 | if (value == 0) | |
3535 | newval &= ~0x60; /* Shifts of zero must be done as lsl */ | |
3536 | else if (value == 32) | |
3537 | value = 0; | |
3538 | newval &= 0xfffff07f; | |
3539 | newval |= (value & 0x1f) << 7; | |
3540 | md_number_to_chars (buf, newval , INSN_SIZE); | |
3541 | break; | |
3542 | ||
3543 | case BFD_RELOC_ARM_SWI: | |
3544 | if (((unsigned long) value) > 0x00ffffff) | |
3545 | as_bad_where (fixP->fx_file, fixP->fx_line, "Invalid swi expression"); | |
3546 | newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000; | |
3547 | newval |= value; | |
3548 | md_number_to_chars (buf, newval , INSN_SIZE); | |
3549 | break; | |
3550 | ||
3551 | case BFD_RELOC_ARM_MULTI: | |
3552 | if (((unsigned long) value) > 0xffff) | |
3553 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
3554 | "Invalid expression in load/store multiple"); | |
3555 | newval = value | md_chars_to_number (buf, INSN_SIZE); | |
3556 | md_number_to_chars (buf, newval, INSN_SIZE); | |
3557 | break; | |
3558 | ||
3559 | case BFD_RELOC_ARM_PCREL_BRANCH: | |
3560 | value = (value >> 2) & 0x00ffffff; | |
3561 | newval = md_chars_to_number (buf, INSN_SIZE); | |
3562 | value = (value + (newval & 0x00ffffff)) & 0x00ffffff; | |
3563 | newval = value | (newval & 0xff000000); | |
3564 | md_number_to_chars (buf, newval, INSN_SIZE); | |
3565 | break; | |
3566 | ||
3567 | case BFD_RELOC_8: | |
3568 | if (fixP->fx_done || fixP->fx_pcrel) | |
3569 | md_number_to_chars (buf, value, 1); | |
3570 | break; | |
3571 | ||
3572 | case BFD_RELOC_16: | |
3573 | if (fixP->fx_done || fixP->fx_pcrel) | |
3574 | md_number_to_chars (buf, value, 2); | |
3575 | break; | |
3576 | ||
3577 | case BFD_RELOC_32: | |
3578 | if (fixP->fx_done || fixP->fx_pcrel) | |
3579 | md_number_to_chars (buf, value, 4); | |
3580 | break; | |
3581 | ||
3582 | case BFD_RELOC_ARM_CP_OFF_IMM: | |
3583 | sign = value >= 0; | |
3584 | if (value < -1023 || value > 1023 || (value & 3)) | |
3585 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
3586 | "Illegal value for co-processor offset"); | |
3587 | if (value < 0) | |
3588 | value = -value; | |
3589 | newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00; | |
3590 | newval |= (value >> 2) | (sign ? 0x00800000 : 0); | |
3591 | md_number_to_chars (buf, newval , INSN_SIZE); | |
3592 | break; | |
3593 | ||
3594 | case BFD_RELOC_NONE: | |
3595 | default: | |
3596 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
3597 | "Bad relocation fixup type (%d)\n", fixP->fx_r_type); | |
3598 | } | |
3599 | ||
3600 | return 1; | |
3601 | } | |
3602 | ||
3603 | /* Translate internal representation of relocation info to BFD target | |
3604 | format. */ | |
3605 | arelent * | |
3606 | tc_gen_reloc (section, fixp) | |
3607 | asection *section; | |
3608 | fixS *fixp; | |
3609 | { | |
3610 | arelent *reloc; | |
3611 | bfd_reloc_code_real_type code; | |
3612 | ||
3613 | reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); | |
3614 | assert (reloc != 0); | |
3615 | ||
3616 | reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; | |
3617 | reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; | |
3618 | ||
3619 | /* @@ Why fx_addnumber sometimes and fx_offset other times? */ | |
3620 | if (fixp->fx_pcrel == 0) | |
3621 | reloc->addend = fixp->fx_offset; | |
3622 | else | |
3623 | reloc->addend = fixp->fx_offset = reloc->address; | |
3624 | ||
3625 | /* @@ Why fx_addnumber sometimes and fx_offset other times? */ | |
3626 | if (fixp->fx_pcrel == 0) | |
3627 | reloc->addend = fixp->fx_offset; | |
3628 | else | |
3629 | reloc->addend = fixp->fx_offset = reloc->address; | |
3630 | ||
3631 | switch (fixp->fx_r_type) | |
3632 | { | |
3633 | case BFD_RELOC_8: | |
3634 | if (fixp->fx_pcrel) | |
3635 | { | |
3636 | code = BFD_RELOC_8_PCREL; | |
3637 | break; | |
3638 | } | |
3639 | ||
3640 | case BFD_RELOC_16: | |
3641 | if (fixp->fx_pcrel) | |
3642 | { | |
3643 | code = BFD_RELOC_16_PCREL; | |
3644 | break; | |
3645 | } | |
3646 | ||
3647 | case BFD_RELOC_32: | |
3648 | if (fixp->fx_pcrel) | |
3649 | { | |
3650 | code = BFD_RELOC_32_PCREL; | |
3651 | break; | |
3652 | } | |
3653 | ||
3654 | case BFD_RELOC_ARM_PCREL_BRANCH: | |
3655 | code = fixp->fx_r_type; | |
3656 | break; | |
3657 | ||
3658 | case BFD_RELOC_ARM_LITERAL: | |
3659 | /* If this is called then the a literal has been referenced across | |
3660 | a section boundry - possibly due to an implicit dump */ | |
3661 | as_bad ("Literal referenced across section boundry (Implicit dump?)"); | |
3662 | return NULL; | |
3663 | ||
3664 | case BFD_RELOC_ARM_IMMEDIATE: | |
3665 | as_bad ("Internal_relocation (type %d) not fixed up (IMMEDIATE)" | |
3666 | , fixp->fx_r_type); | |
3667 | return NULL; | |
3668 | ||
3669 | case BFD_RELOC_ARM_OFFSET_IMM: | |
3670 | as_bad ("Internal_relocation (type %d) not fixed up (OFFSET_IMM)" | |
3671 | , fixp->fx_r_type); | |
3672 | return NULL; | |
3673 | ||
3674 | case BFD_RELOC_ARM_SHIFT_IMM: | |
3675 | as_bad ("Internal_relocation (type %d) not fixed up (SHIFT_IMM)" | |
3676 | , fixp->fx_r_type); | |
3677 | return NULL; | |
3678 | ||
3679 | case BFD_RELOC_ARM_SWI: | |
3680 | as_bad ("Internal_relocation (type %d) not fixed up (SWI)" | |
3681 | , fixp->fx_r_type); | |
3682 | return NULL; | |
3683 | ||
3684 | case BFD_RELOC_ARM_MULTI: | |
3685 | as_bad ("Internal_relocation (type %d) not fixed up (MULTI)" | |
3686 | , fixp->fx_r_type); | |
3687 | return NULL; | |
3688 | ||
3689 | case BFD_RELOC_ARM_CP_OFF_IMM: | |
3690 | as_bad ("Internal_relocation (type %d) not fixed up (CP_OFF_IMM)" | |
3691 | , fixp->fx_r_type); | |
3692 | return NULL; | |
3693 | ||
3694 | default: | |
3695 | abort (); | |
3696 | } | |
3697 | ||
3698 | reloc->howto = bfd_reloc_type_lookup (stdoutput, code); | |
3699 | assert (reloc->howto != 0); | |
3700 | ||
3701 | return reloc; | |
3702 | } | |
3703 | ||
3704 | CONST int md_short_jump_size = 4; | |
3705 | CONST int md_long_jump_size = 4; | |
3706 | ||
3707 | /* These should never be called on the arm */ | |
3708 | void | |
3709 | md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) | |
3710 | char *ptr; | |
3711 | addressT from_addr, to_addr; | |
3712 | fragS *frag; | |
3713 | symbolS *to_symbol; | |
3714 | { | |
3715 | as_fatal ("md_create_long_jump\n"); | |
3716 | } | |
3717 | ||
3718 | void | |
3719 | md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) | |
3720 | char *ptr; | |
3721 | addressT from_addr, to_addr; | |
3722 | fragS *frag; | |
3723 | symbolS *to_symbol; | |
3724 | { | |
3725 | as_fatal ("md_create_short_jump\n"); | |
3726 | } | |
3727 | ||
3728 | int | |
3729 | md_estimate_size_before_relax (fragP, segtype) | |
3730 | fragS *fragP; | |
3731 | segT segtype; | |
3732 | { | |
3733 | as_fatal ("md_estimate_size_before_relax\n"); | |
3734 | return (1); | |
3735 | } | |
3736 | ||
3737 | void | |
3738 | output_inst (str) | |
3739 | char *str; | |
3740 | { | |
3741 | char *to = NULL; | |
3742 | ||
3743 | if (inst.error) | |
3744 | { | |
3745 | as_bad ("%s -- statement `%s'\n", inst.error, str); | |
3746 | return; | |
3747 | } | |
3748 | ||
3749 | to = frag_more (INSN_SIZE); | |
3750 | md_number_to_chars (to, inst.instruction, INSN_SIZE); | |
3751 | ||
3752 | if (inst.reloc.type != BFD_RELOC_NONE) | |
3753 | fix_new_arm (frag_now, to - frag_now->fr_literal, | |
3754 | 4, &inst.reloc.exp, inst.reloc.pc_rel, | |
3755 | inst.reloc.type); | |
3756 | ||
3757 | return; | |
3758 | } | |
3759 | ||
3760 | void | |
3761 | md_assemble (str) | |
3762 | char *str; | |
3763 | { | |
3764 | char c; | |
3765 | CONST struct asm_opcode *opcode; | |
3766 | char *p, *q, *start; | |
3767 | ||
3768 | /* Align the instruction */ | |
3769 | /* this may not be the right thing to do but ... */ | |
3770 | /* arm_align (2, 0); */ | |
3771 | listing_prev_line (); /* Defined in listing.h */ | |
3772 | ||
3773 | /* Align the previous label if needed */ | |
3774 | if (last_label_seen != NULL) | |
3775 | { | |
3776 | last_label_seen->sy_frag = frag_now; | |
3777 | S_SET_VALUE (last_label_seen, | |
3778 | (valueT) ((char *) obstack_next_free (&frags) | |
3779 | - frag_now->fr_literal)); | |
3780 | S_SET_SEGMENT (last_label_seen, now_seg); | |
3781 | } | |
3782 | ||
3783 | memset (&inst, '\0', sizeof (inst)); | |
3784 | inst.reloc.type = BFD_RELOC_NONE; | |
3785 | ||
3786 | if (*str == ' ') | |
3787 | str++; /* Skip leading white space */ | |
3788 | ||
3789 | /* scan up to the end of the op-code, which must end in white space or | |
3790 | end of string */ | |
3791 | for (start = p = str; *p != '\0'; p++) | |
3792 | if (*p == ' ') | |
3793 | break; | |
3794 | ||
3795 | if (p == str) | |
3796 | { | |
3797 | as_bad ("No operator -- statement `%s'\n", str); | |
3798 | return; | |
3799 | } | |
3800 | ||
3801 | /* p now points to the end of the opcode, probably white space, but we have | |
3802 | to break the opcode up in case it contains condionals and flags; | |
3803 | keep trying with progressively smaller basic instructions until one | |
3804 | matches, or we run out of opcode. */ | |
3805 | q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p; | |
3806 | for (; q != str; q--) | |
3807 | { | |
3808 | c = *q; | |
3809 | *q = '\0'; | |
3810 | opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str); | |
3811 | *q = c; | |
3812 | if (opcode && opcode->template) | |
3813 | { | |
3814 | unsigned long flag_bits = 0; | |
3815 | char *r; | |
3816 | ||
3817 | /* Check that this instruction is supported for this CPU */ | |
3818 | if ((opcode->variants & cpu_variant) == 0) | |
3819 | goto try_shorter; | |
3820 | ||
3821 | inst.instruction = opcode->value; | |
3822 | if (q == p) /* Just a simple opcode */ | |
3823 | { | |
3824 | if (opcode->comp_suffix != 0) | |
3825 | as_bad ("Opcode `%s' must have suffix from <%s>\n", str, | |
3826 | opcode->comp_suffix); | |
3827 | else | |
3828 | { | |
3829 | inst.instruction |= COND_ALWAYS; | |
3830 | (*opcode->parms)(q, 0); | |
3831 | } | |
3832 | output_inst (start); | |
3833 | return; | |
3834 | } | |
3835 | ||
3836 | /* Now check for a conditional */ | |
3837 | r = q; | |
3838 | if (p - r >= 2) | |
3839 | { | |
3840 | CONST struct asm_cond *cond; | |
3841 | char d = *(r + 2); | |
3842 | ||
3843 | *(r + 2) = '\0'; | |
3844 | cond = (CONST struct asm_cond *) hash_find (arm_cond_hsh, r); | |
3845 | *(r + 2) = d; | |
3846 | if (cond) | |
3847 | { | |
3848 | if (cond->value == 0xf0000000) | |
3849 | as_tsktsk | |
3850 | ("Warning: Use of the 'nv' conditional is deprecated\n"); | |
3851 | ||
3852 | inst.instruction |= cond->value; | |
3853 | r += 2; | |
3854 | } | |
3855 | else | |
3856 | inst.instruction |= COND_ALWAYS; | |
3857 | } | |
3858 | else | |
3859 | inst.instruction |= COND_ALWAYS; | |
3860 | ||
3861 | /* if there is a compulsory suffix, it should come here, before | |
3862 | any optional flags. */ | |
3863 | if (opcode->comp_suffix) | |
3864 | { | |
3865 | CONST char *s = opcode->comp_suffix; | |
3866 | ||
3867 | while (*s) | |
3868 | { | |
3869 | inst.suffix++; | |
3870 | if (*r == *s) | |
3871 | break; | |
3872 | s++; | |
3873 | } | |
3874 | ||
3875 | if (*s == '\0') | |
3876 | { | |
3877 | as_bad ("Opcode `%s' must have suffix from <%s>\n", str, | |
3878 | opcode->comp_suffix); | |
3879 | return; | |
3880 | } | |
3881 | ||
3882 | r++; | |
3883 | } | |
3884 | ||
3885 | /* The remainder, if any should now be flags for the instruction; | |
3886 | Scan these checking each one found with the opcode. */ | |
3887 | if (r != p) | |
3888 | { | |
3889 | char d; | |
3890 | CONST struct asm_flg *flag = opcode->flags; | |
3891 | ||
3892 | if (flag) | |
3893 | { | |
3894 | int flagno; | |
3895 | ||
3896 | d = *p; | |
3897 | *p = '\0'; | |
3898 | ||
3899 | for (flagno = 0; flag[flagno].template; flagno++) | |
3900 | { | |
3901 | if (! strcmp (r, flag[flagno].template)) | |
3902 | { | |
3903 | flag_bits |= flag[flagno].set_bits; | |
3904 | break; | |
3905 | } | |
3906 | } | |
3907 | ||
3908 | *p = d; | |
3909 | if (! flag[flagno].template) | |
3910 | goto try_shorter; | |
3911 | } | |
3912 | else | |
3913 | goto try_shorter; | |
3914 | } | |
3915 | ||
3916 | (*opcode->parms) (p, flag_bits); | |
3917 | output_inst (start); | |
3918 | return; | |
3919 | } | |
3920 | ||
3921 | try_shorter: | |
3922 | ; | |
3923 | } | |
3924 | /* It wasn't an instruction, but it might be a register alias of the form | |
3925 | alias .req reg | |
3926 | */ | |
3927 | q = p; | |
3928 | while (*q == ' ') | |
3929 | q++; | |
3930 | ||
3931 | c = *p; | |
3932 | *p = '\0'; | |
3933 | ||
3934 | if (*q && !strncmp (q, ".req ", 4)) | |
3935 | { | |
3936 | int reg; | |
3937 | if ((reg = arm_reg_parse (&str)) == FAIL) | |
3938 | { | |
3939 | char *r; | |
3940 | ||
3941 | q += 4; | |
3942 | while (*q == ' ') | |
3943 | q++; | |
3944 | ||
3945 | for (r = q; *r != '\0'; r++) | |
3946 | if (*r == ' ') | |
3947 | break; | |
3948 | ||
3949 | if (r != q) | |
3950 | { | |
3951 | int regnum; | |
3952 | char d = *r; | |
3953 | ||
3954 | *r = '\0'; | |
3955 | regnum = arm_reg_parse (&q); | |
3956 | *r = d; | |
3957 | if (regnum != FAIL) | |
3958 | { | |
3959 | insert_reg_alias (str, regnum); | |
3960 | *p = c; | |
3961 | return; | |
3962 | } | |
3963 | } | |
3964 | } | |
3965 | else | |
3966 | { | |
3967 | *p = c; | |
3968 | return; | |
3969 | } | |
3970 | } | |
3971 | ||
3972 | *p = c; | |
3973 | as_bad ("bad instruction `%s'", start); | |
3974 | } | |
3975 | ||
3976 | /* | |
3977 | * md_parse_option | |
3978 | * Invocation line includes a switch not recognized by the base assembler. | |
3979 | * See if it's a processor-specific option. These are: | |
3980 | * Cpu variants, the arm part is optional: | |
3981 | * -m[arm]1 Currently not supported. | |
3982 | * -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor | |
3983 | * -m[arm]3 Arm 3 processor | |
3984 | * -m[arm]6, -m[arm]7 Arm 6 and 7 processors | |
3985 | * -m[arm]7dm Arm 7dm processors | |
3986 | * -mall All (except the ARM1) | |
3987 | * FP variants: | |
3988 | * -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions | |
3989 | * -mfpe-old (No float load/store multiples) | |
3990 | * -mno-fpu Disable all floating point instructions | |
3991 | * Run-time endian selection: | |
3992 | * -EB big endian cpu | |
3993 | * -EL little endian cpu | |
3994 | */ | |
3995 | ||
3996 | CONST char *md_shortopts = "m:"; | |
3997 | struct option md_longopts[] = { | |
3998 | #ifdef ARM_BI_ENDIAN | |
3999 | #define OPTION_EB (OPTION_MD_BASE + 0) | |
4000 | {"EB", no_argument, NULL, OPTION_EB}, | |
4001 | #define OPTION_EL (OPTION_MD_BASE + 1) | |
4002 | {"EL", no_argument, NULL, OPTION_EL}, | |
4003 | #endif | |
4004 | {NULL, no_argument, NULL, 0} | |
4005 | }; | |
4006 | size_t md_longopts_size = sizeof(md_longopts); | |
4007 | ||
4008 | int | |
4009 | md_parse_option (c, arg) | |
4010 | int c; | |
4011 | char *arg; | |
4012 | { | |
4013 | char *str = arg; | |
4014 | ||
4015 | switch (c) | |
4016 | { | |
4017 | #ifdef ARM_BI_ENDIAN | |
4018 | case OPTION_EB: | |
4019 | target_big_endian = 1; | |
4020 | break; | |
4021 | case OPTION_EL: | |
4022 | target_big_endian = 0; | |
4023 | break; | |
4024 | #endif | |
4025 | ||
4026 | case 'm': | |
4027 | switch (*str) | |
4028 | { | |
4029 | case 'f': | |
4030 | if (! strcmp (str, "fpa10")) | |
4031 | cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA10; | |
4032 | else if (! strcmp (str, "fpa11")) | |
4033 | cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA11; | |
4034 | else if (! strcmp (str, "fpe-old")) | |
4035 | cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_CORE; | |
4036 | else | |
4037 | goto bad; | |
4038 | break; | |
4039 | ||
4040 | case 'n': | |
4041 | if (! strcmp (str, "no-fpu")) | |
4042 | cpu_variant &= ~FPU_ALL; | |
4043 | break; | |
4044 | ||
4045 | default: | |
4046 | if (! strcmp (str, "all")) | |
4047 | { | |
4048 | cpu_variant = ARM_ALL | FPU_ALL; | |
4049 | return 1; | |
4050 | } | |
4051 | ||
4052 | /* Strip off optional "arm" */ | |
4053 | if (! strncmp (str, "arm", 3)) | |
4054 | str += 3; | |
4055 | ||
4056 | switch (*str) | |
4057 | { | |
4058 | case '1': | |
4059 | if (! strcmp (str, "1")) | |
4060 | cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_1; | |
4061 | else | |
4062 | goto bad; | |
4063 | break; | |
4064 | ||
4065 | case '2': | |
4066 | if (! strcmp (str, "2")) | |
4067 | cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; | |
4068 | else if (! strcmp (str, "250")) | |
4069 | cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_250; | |
4070 | else | |
4071 | goto bad; | |
4072 | break; | |
4073 | ||
4074 | case '3': | |
4075 | if (! strcmp (str, "3")) | |
4076 | cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; | |
4077 | else | |
4078 | goto bad; | |
4079 | break; | |
4080 | ||
4081 | case '6': | |
4082 | if (! strcmp (str, "6")) | |
4083 | cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6; | |
4084 | else | |
4085 | goto bad; | |
4086 | break; | |
4087 | ||
4088 | case '7': | |
4089 | if (! strcmp (str, "7")) | |
4090 | cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7; | |
4091 | else if (! strcmp (str, "7dm")) | |
4092 | cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7DM; | |
4093 | else | |
4094 | goto bad; | |
4095 | break; | |
4096 | ||
4097 | default: | |
4098 | bad: | |
4099 | as_bad ("Invalid architecture -m%s", arg); | |
4100 | return 0; | |
4101 | } | |
4102 | } | |
4103 | break; | |
4104 | ||
4105 | default: | |
4106 | return 0; | |
4107 | } | |
4108 | ||
4109 | return 1; | |
4110 | } | |
4111 | ||
4112 | void | |
4113 | md_show_usage (fp) | |
4114 | FILE *fp; | |
4115 | { | |
4116 | fprintf (fp, | |
4117 | "-m[arm]1, -m[arm]2, -m[arm]250,\n-m[arm]3, -m[arm]6, -m[arm]7, -m[arm]7dm\n\ | |
4118 | \t\t\tselect processor architecture\n\ | |
4119 | -mall\t\t\tallow any instruction\n\ | |
4120 | -mfpa10, -mfpa11\tselect floating point architecture\n\ | |
4121 | -mfpe-old\t\tdon't allow floating-point multiple instructions\n\ | |
4122 | -mno-fpu\t\tdon't allow any floating-point instructions.\n"); | |
4123 | #ifdef ARM_BI_ENDIAN | |
4124 | fprintf (fp, | |
4125 | "-EB\t\t\tassemble code for a big endian cpu\n\ | |
4126 | -EL\t\t\tassemble code for a little endian cpu\n"); | |
4127 | #endif | |
4128 | } | |
4129 | ||
4130 | /* We need to be able to fix up arbitrary expressions in some statements. | |
4131 | This is so that we can handle symbols that are an arbitrary distance from | |
4132 | the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask), | |
4133 | which returns part of an address in a form which will be valid for | |
4134 | a data instruction. We do this by pushing the expression into a symbol | |
4135 | in the expr_section, and creating a fix for that. */ | |
4136 | ||
4137 | static void | |
4138 | fix_new_arm (frag, where, size, exp, pc_rel, reloc) | |
4139 | fragS *frag; | |
4140 | int where; | |
4141 | short int size; | |
4142 | expressionS *exp; | |
4143 | int pc_rel; | |
4144 | int reloc; | |
4145 | { | |
4146 | fixS *new_fix; | |
4147 | ||
4148 | switch (exp->X_op) | |
4149 | { | |
4150 | case O_constant: | |
4151 | case O_symbol: | |
4152 | case O_add: | |
4153 | case O_subtract: | |
4154 | new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc); | |
4155 | break; | |
4156 | ||
4157 | default: | |
4158 | { | |
4159 | const char *fake; | |
4160 | symbolS *symbolP; | |
4161 | ||
4162 | /* FIXME: This should be something which decode_local_label_name | |
4163 | will handle. */ | |
4164 | fake = FAKE_LABEL_NAME; | |
4165 | ||
4166 | /* Putting constant symbols in absolute_section rather than | |
4167 | expr_section is convenient for the old a.out code, for which | |
4168 | S_GET_SEGMENT does not always retrieve the value put in by | |
4169 | S_SET_SEGMENT. */ | |
4170 | symbolP = symbol_new (fake, expr_section, 0, &zero_address_frag); | |
4171 | symbolP->sy_value = *exp; | |
4172 | new_fix = fix_new (frag, where, size, symbolP, 0, pc_rel, reloc); | |
4173 | } | |
4174 | break; | |
4175 | } | |
4176 | ||
4177 | return; | |
4178 | } | |
4179 | ||
4180 | /* A good place to do this, although this was probably not intended | |
4181 | * for this kind of use. We need to dump the literal pool before | |
4182 | * references are made to a null symbol pointer. */ | |
4183 | void | |
4184 | arm_after_pass_hook (ignore) | |
4185 | asection *ignore; | |
4186 | { | |
4187 | if (current_poolP != NULL) | |
4188 | { | |
4189 | subseg_set (text_section, 0); /* Put it at the end of text section */ | |
4190 | s_ltorg (0); | |
4191 | listing_prev_line (); | |
4192 | } | |
4193 | } | |
4194 | ||
4195 | void | |
4196 | arm_start_line_hook () | |
4197 | { | |
4198 | last_label_seen = NULL; | |
4199 | } | |
4200 | ||
4201 | void | |
4202 | arm_frob_label (sym) | |
4203 | symbolS *sym; | |
4204 | { | |
4205 | last_label_seen = sym; | |
4206 | } |