Commit | Line | Data |
---|---|---|
5749c497 KR |
1 | /* tc-alpha.c - Processor-specific code for the DEC Alpha CPU. |
2 | Copyright (C) 1989, 1993, 1994 Free Software Foundation, Inc. | |
3 | Contributed by Carnegie Mellon University, 1993. | |
4 | Written by Alessandro Forin, based on earlier gas-1.38 target CPU files. | |
5 | Modified by Ken Raeburn for gas-2.x and ECOFF support. | |
6 | ||
7 | This file is part of GAS, the GNU Assembler. | |
8 | ||
9 | GAS is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GAS is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GAS; see the file COPYING. If not, write to | |
21 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
22 | ||
23 | /* | |
24 | * Mach Operating System | |
25 | * Copyright (c) 1993 Carnegie Mellon University | |
26 | * All Rights Reserved. | |
27 | * | |
28 | * Permission to use, copy, modify and distribute this software and its | |
29 | * documentation is hereby granted, provided that both the copyright | |
30 | * notice and this permission notice appear in all copies of the | |
31 | * software, derivative works or modified versions, and any portions | |
32 | * thereof, and that both notices appear in supporting documentation. | |
33 | * | |
34 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS | |
35 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
36 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
37 | * | |
38 | * Carnegie Mellon requests users of this software to return to | |
39 | * | |
40 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
41 | * School of Computer Science | |
42 | * Carnegie Mellon University | |
43 | * Pittsburgh PA 15213-3890 | |
44 | * | |
45 | * any improvements or extensions that they make and grant Carnegie the | |
46 | * rights to redistribute these changes. | |
47 | */ | |
48 | /* | |
49 | * HISTORY | |
50 | * 5-Oct-93 Alessandro Forin (af) at Carnegie-Mellon University | |
51 | * First Checkin | |
52 | * | |
5749c497 KR |
53 | * Author: Alessandro Forin, Carnegie Mellon University |
54 | * Date: Jan 1993 | |
55 | */ | |
56 | ||
a2a1a548 ILT |
57 | #include <ctype.h> |
58 | ||
5749c497 KR |
59 | #include "as.h" |
60 | #include "alpha-opcode.h" | |
61 | #include "subsegs.h" | |
62 | ||
30869211 KR |
63 | /* @@ Will a simple 0x8000 work here? If not, why not? */ |
64 | #define GP_ADJUSTMENT (0x8000 - 0x10) | |
65 | ||
5749c497 KR |
66 | /* These are exported to relaxing code, even though we don't do any |
67 | relaxing on this processor currently. */ | |
5749c497 KR |
68 | int md_short_jump_size = 4; |
69 | int md_long_jump_size = 4; | |
70 | ||
71 | /* handle of the OPCODE hash table */ | |
72 | static struct hash_control *op_hash; | |
73 | ||
40cd35ff KR |
74 | /* Sections and symbols we'll want to keep track of. */ |
75 | static segT lita_sec, rdata, sdata, lit8_sec, lit4_sec; | |
76 | static symbolS *lit8_sym, *lit4_sym; | |
5749c497 | 77 | |
40cd35ff | 78 | /* Setting for ".set [no]{at,macro}". */ |
5749c497 KR |
79 | static int at_ok = 1, macro_ok = 1; |
80 | ||
81 | /* Keep track of global pointer. */ | |
c79e67a3 | 82 | valueT alpha_gp_value; |
5749c497 KR |
83 | static symbolS *gp; |
84 | ||
85 | /* We'll probably be using this relocation frequently, and we | |
86 | will want to compare for it. */ | |
265d172e | 87 | static reloc_howto_type *gpdisp_hi16_howto; |
5749c497 KR |
88 | |
89 | /* These are exported to ECOFF code. */ | |
90 | unsigned long alpha_gprmask, alpha_fprmask; | |
91 | ||
92 | /* Used for LITUSE relocations. */ | |
93 | static expressionS lituse_basereg, lituse_byteoff, lituse_jsr; | |
94 | ||
cf272f02 KR |
95 | /* Address size: In OSF/1 1.3, an undocumented "-32addr" option will |
96 | cause all addresses to be treated as 32-bit values in memory. (The | |
97 | in-register versions are all sign-extended to 64 bits, of course.) | |
98 | Some other systems may want this option too. */ | |
99 | static int addr32; | |
100 | ||
265d172e ILT |
101 | /* Symbol labelling the current insn. When the Alpha gas sees |
102 | foo: | |
103 | .quad 0 | |
104 | and the section happens to not be on an eight byte boundary, it | |
105 | will align both the symbol and the .quad to an eight byte boundary. */ | |
106 | static symbolS *insn_label; | |
107 | ||
108 | /* Whether we should automatically align data generation pseudo-ops. | |
109 | .align 0 will turn this off. */ | |
110 | static int auto_align = 1; | |
111 | ||
5749c497 KR |
112 | /* Imported functions -- they should be defined in header files somewhere. */ |
113 | extern segT subseg_get (); | |
114 | extern PTR bfd_alloc_by_size_t (); | |
115 | extern void s_globl (), s_long (), s_short (), s_space (), cons (), s_text (), | |
116 | s_data (), float_cons (); | |
117 | ||
c79e67a3 | 118 | /* Static functions, needing forward declarations. */ |
a2a1a548 | 119 | static void s_base (), s_proc (), s_alpha_set (); |
5749c497 | 120 | static void s_gprel32 (), s_rdata (), s_sdata (), s_alpha_comm (); |
265d172e ILT |
121 | static void s_alpha_text PARAMS ((int)); |
122 | static void s_alpha_data PARAMS ((int)); | |
123 | static void s_alpha_align PARAMS ((int)); | |
124 | static void s_alpha_cons PARAMS ((int)); | |
125 | static void s_alpha_float_cons PARAMS ((int)); | |
5749c497 KR |
126 | static int alpha_ip (); |
127 | ||
aaeee550 KR |
128 | static void emit_unaligned_io PARAMS ((char *, int, valueT, int)); |
129 | static void emit_load_unal PARAMS ((int, valueT, int)); | |
130 | static void emit_store_unal PARAMS ((int, valueT, int)); | |
131 | static void emit_byte_manip_r PARAMS ((char *, int, int, int, int, int)); | |
132 | static void emit_extract_r PARAMS ((int, int, int, int, int)); | |
133 | static void emit_insert_r PARAMS ((int, int, int, int, int)); | |
134 | static void emit_mask_r PARAMS ((int, int, int, int, int)); | |
135 | static void emit_sign_extend PARAMS ((int, int)); | |
136 | static void emit_bis_r PARAMS ((int, int, int)); | |
137 | static int build_mem PARAMS ((int, int, int, bfd_signed_vma)); | |
138 | static int build_operate_n PARAMS ((int, int, int, int, int)); | |
139 | static void emit_sll_n PARAMS ((int, int, int)); | |
140 | static void emit_ldah_num PARAMS ((int, bfd_vma, int)); | |
141 | static void emit_addq_r PARAMS ((int, int, int)); | |
142 | static void emit_lda_n PARAMS ((int, bfd_vma, int)); | |
143 | static void emit_add64 PARAMS ((int, int, bfd_vma)); | |
71f9b3c0 | 144 | static int in_range_signed PARAMS ((bfd_vma, int)); |
265d172e | 145 | static void alpha_align PARAMS ((int, int, symbolS *)); |
aaeee550 | 146 | |
5749c497 KR |
147 | const pseudo_typeS md_pseudo_table[] = |
148 | { | |
149 | {"common", s_comm, 0}, /* is this used? */ | |
150 | {"comm", s_alpha_comm, 0}, /* osf1 compiler does this */ | |
265d172e ILT |
151 | {"text", s_alpha_text, 0}, |
152 | {"data", s_alpha_data, 0}, | |
5749c497 KR |
153 | {"rdata", s_rdata, 0}, |
154 | {"sdata", s_sdata, 0}, | |
155 | {"gprel32", s_gprel32, 0}, | |
265d172e ILT |
156 | {"t_floating", s_alpha_float_cons, 'd'}, |
157 | {"s_floating", s_alpha_float_cons, 'f'}, | |
158 | {"f_floating", s_alpha_float_cons, 'F'}, | |
159 | {"g_floating", s_alpha_float_cons, 'G'}, | |
160 | {"d_floating", s_alpha_float_cons, 'D'}, | |
5749c497 KR |
161 | |
162 | {"proc", s_proc, 0}, | |
163 | {"aproc", s_proc, 1}, | |
164 | {"set", s_alpha_set, 0}, | |
165 | {"reguse", s_ignore, 0}, | |
166 | {"livereg", s_ignore, 0}, | |
167 | {"extern", s_ignore, 0}, /*??*/ | |
168 | {"base", s_base, 0}, /*??*/ | |
169 | {"option", s_ignore, 0}, | |
170 | {"prologue", s_ignore, 0}, | |
171 | {"aent", s_ignore, 0}, | |
172 | {"ugen", s_ignore, 0}, | |
173 | ||
265d172e ILT |
174 | {"align", s_alpha_align, 0}, |
175 | {"byte", s_alpha_cons, 0}, | |
176 | {"hword", s_alpha_cons, 1}, | |
177 | {"int", s_alpha_cons, 2}, | |
178 | {"long", s_alpha_cons, 2}, | |
179 | {"octa", s_alpha_cons, 4}, | |
180 | {"quad", s_alpha_cons, 3}, | |
181 | {"short", s_alpha_cons, 1}, | |
182 | {"word", s_alpha_cons, 1}, | |
183 | {"double", s_alpha_float_cons, 'd'}, | |
184 | {"float", s_alpha_float_cons, 'f'}, | |
185 | {"single", s_alpha_float_cons, 'f'}, | |
186 | ||
5749c497 KR |
187 | /* We don't do any optimizing, so we can safely ignore these. */ |
188 | {"noalias", s_ignore, 0}, | |
189 | {"alias", s_ignore, 0}, | |
190 | ||
191 | {NULL, 0, 0}, | |
192 | }; | |
193 | ||
194 | #define SA 21 /* shift for register Ra */ | |
195 | #define SB 16 /* shift for register Rb */ | |
196 | #define SC 0 /* shift for register Rc */ | |
197 | #define SN 13 /* shift for 8 bit immediate # */ | |
198 | ||
199 | #define T9 23 | |
200 | #define T10 24 | |
201 | #define T11 25 | |
0952861c KR |
202 | #define T12 26 |
203 | #define RA 26 /* note: same as T12 */ | |
5749c497 KR |
204 | #define PV 27 |
205 | #define AT 28 | |
206 | #define GP 29 | |
207 | #define SP 30 | |
208 | #define ZERO 31 | |
209 | ||
210 | #define OPCODE(X) (((X) >> 26) & 0x3f) | |
211 | #define OP_FCN(X) (((X) >> 5) & 0x7f) | |
212 | ||
213 | #ifndef FIRST_32BIT_QUADRANT | |
214 | #define FIRST_32BIT_QUADRANT 0 | |
215 | #endif | |
216 | ||
217 | int first_32bit_quadrant = FIRST_32BIT_QUADRANT; | |
218 | int base_register = FIRST_32BIT_QUADRANT ? ZERO : GP; | |
219 | ||
220 | int no_mixed_code = 0; | |
221 | int nofloats = 0; | |
222 | ||
223 | /* This array holds the chars that always start a comment. If the | |
224 | pre-processor is disabled, these aren't very useful */ | |
225 | const char comment_chars[] = "#"; | |
226 | ||
227 | /* This array holds the chars that only start a comment at the beginning of | |
228 | a line. If the line seems to have the form '# 123 filename' | |
229 | .line and .file directives will appear in the pre-processed output */ | |
230 | /* Note that input_file.c hand checks for '#' at the beginning of the | |
231 | first line of the input file. This is because the compiler outputs | |
232 | #NO_APP at the beginning of its output. */ | |
a2a1a548 | 233 | /* Also note that C style comments are always recognized. */ |
30869211 | 234 | const char line_comment_chars[] = "#!"; |
5749c497 KR |
235 | |
236 | /* Chars that can be used to separate mant from exp in floating point nums */ | |
237 | const char EXP_CHARS[] = "eE"; | |
238 | ||
239 | const char line_separator_chars[1]; | |
240 | ||
241 | /* Chars that mean this number is a floating point constant, as in | |
242 | "0f12.456" or "0d1.2345e12". */ | |
0952861c | 243 | /* @@ Do all of these really get used on the alpha?? */ |
5749c497 KR |
244 | char FLT_CHARS[] = "rRsSfFdDxXpP"; |
245 | ||
246 | /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be | |
247 | changed in read.c. Ideally it shouldn't have to know about it at all, | |
248 | but nothing is ideal around here. */ | |
249 | ||
250 | struct reloc_data { | |
251 | expressionS exp; | |
252 | int pcrel; | |
253 | bfd_reloc_code_real_type code; | |
254 | }; | |
255 | ||
256 | /* Occasionally, two relocations will be desired for one address. | |
257 | Mainly only in cases like "jsr $r,foo" where we want both a LITUSE | |
258 | and a HINT reloc. */ | |
259 | #define MAX_RELOCS 2 | |
260 | ||
261 | struct alpha_it { | |
262 | unsigned long opcode; /* need at least 32 bits */ | |
263 | struct reloc_data reloc[MAX_RELOCS]; | |
264 | }; | |
265 | ||
c79e67a3 | 266 | static void getExpression (char *str, struct alpha_it *insn); |
5749c497 KR |
267 | static char *expr_end; |
268 | ||
269 | #define note_gpreg(R) (alpha_gprmask |= (1 << (R))) | |
270 | #define note_fpreg(R) (alpha_fprmask |= (1 << (R))) | |
271 | ||
272 | int | |
273 | tc_get_register (frame) | |
274 | int frame; | |
275 | { | |
5749c497 KR |
276 | int framereg = SP; |
277 | ||
278 | SKIP_WHITESPACE (); | |
279 | if (*input_line_pointer == '$') | |
280 | { | |
281 | input_line_pointer++; | |
282 | if (input_line_pointer[0] == 's' | |
283 | && input_line_pointer[1] == 'p') | |
284 | { | |
285 | input_line_pointer += 2; | |
286 | framereg = SP; | |
287 | } | |
288 | else | |
289 | framereg = get_absolute_expression (); | |
290 | framereg &= 31; /* ? */ | |
291 | } | |
292 | else | |
293 | as_warn ("frame reg expected, using $%d.", framereg); | |
294 | ||
295 | note_gpreg (framereg); | |
296 | return framereg; | |
297 | } | |
298 | ||
265d172e ILT |
299 | /* Handle the .text pseudo-op. This is like the usual one, but it |
300 | clears insn_label and restores auto alignment. */ | |
301 | ||
302 | static void | |
303 | s_alpha_text (i) | |
304 | int i; | |
305 | { | |
306 | s_text (i); | |
307 | insn_label = NULL; | |
308 | auto_align = 1; | |
309 | } | |
310 | ||
311 | /* Handle the .data pseudo-op. This is like the usual one, but it | |
312 | clears insn_label and restores auto alignment. */ | |
313 | ||
314 | static void | |
315 | s_alpha_data (i) | |
316 | int i; | |
317 | { | |
318 | s_data (i); | |
319 | insn_label = NULL; | |
320 | auto_align = 1; | |
321 | } | |
322 | ||
5749c497 KR |
323 | static void |
324 | s_rdata (ignore) | |
325 | int ignore; | |
326 | { | |
327 | int temp; | |
328 | ||
329 | temp = get_absolute_expression (); | |
330 | #if 0 | |
331 | if (!rdata) | |
332 | rdata = subseg_get (".rdata", 0); | |
333 | subseg_set (rdata, (subsegT) temp); | |
334 | #else | |
335 | rdata = subseg_new (".rdata", 0); | |
336 | #endif | |
337 | demand_empty_rest_of_line (); | |
265d172e ILT |
338 | insn_label = NULL; |
339 | auto_align = 1; | |
5749c497 KR |
340 | } |
341 | ||
342 | static void | |
343 | s_sdata (ignore) | |
344 | int ignore; | |
345 | { | |
346 | int temp; | |
347 | ||
348 | temp = get_absolute_expression (); | |
349 | #if 0 | |
350 | if (!sdata) | |
351 | sdata = subseg_get (".sdata", 0); | |
352 | subseg_set (sdata, (subsegT) temp); | |
353 | #else | |
354 | sdata = subseg_new (".sdata", 0); | |
355 | #endif | |
356 | demand_empty_rest_of_line (); | |
265d172e ILT |
357 | insn_label = NULL; |
358 | auto_align = 1; | |
5749c497 KR |
359 | } |
360 | ||
361 | static void | |
362 | s_alpha_comm (ignore) | |
363 | int ignore; | |
364 | { | |
365 | register char *name; | |
366 | register char c; | |
367 | register char *p; | |
368 | offsetT temp; | |
369 | register symbolS *symbolP; | |
370 | ||
371 | name = input_line_pointer; | |
372 | c = get_symbol_end (); | |
373 | /* just after name is now '\0' */ | |
374 | p = input_line_pointer; | |
375 | *p = c; | |
376 | SKIP_WHITESPACE (); | |
377 | /* Alpha OSF/1 compiler doesn't provide the comma, gcc does. */ | |
378 | if (*input_line_pointer == ',') | |
379 | { | |
380 | input_line_pointer++; | |
381 | SKIP_WHITESPACE (); | |
382 | } | |
383 | if ((temp = get_absolute_expression ()) < 0) | |
384 | { | |
385 | as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp); | |
386 | ignore_rest_of_line (); | |
387 | return; | |
388 | } | |
389 | *p = 0; | |
390 | symbolP = symbol_find_or_make (name); | |
391 | *p = c; | |
392 | if (S_IS_DEFINED (symbolP)) | |
393 | { | |
394 | as_bad ("Ignoring attempt to re-define symbol"); | |
395 | ignore_rest_of_line (); | |
396 | return; | |
397 | } | |
398 | if (S_GET_VALUE (symbolP)) | |
399 | { | |
400 | if (S_GET_VALUE (symbolP) != (valueT) temp) | |
401 | as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.", | |
402 | S_GET_NAME (symbolP), | |
403 | (long) S_GET_VALUE (symbolP), | |
404 | (long) temp); | |
405 | } | |
406 | else | |
407 | { | |
408 | S_SET_VALUE (symbolP, (valueT) temp); | |
409 | S_SET_EXTERNAL (symbolP); | |
410 | } | |
411 | ||
412 | know (symbolP->sy_frag == &zero_address_frag); | |
413 | demand_empty_rest_of_line (); | |
414 | } | |
415 | ||
5749c497 KR |
416 | arelent * |
417 | tc_gen_reloc (sec, fixp) | |
418 | asection *sec; | |
419 | fixS *fixp; | |
420 | { | |
421 | arelent *reloc; | |
5749c497 KR |
422 | |
423 | reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); | |
424 | reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; | |
425 | reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; | |
426 | ||
a2a1a548 | 427 | if (fixp->fx_r_type > BFD_RELOC_UNUSED) |
5749c497 KR |
428 | abort (); |
429 | ||
430 | if (fixp->fx_r_type == BFD_RELOC_ALPHA_GPDISP_HI16) | |
431 | { | |
432 | if (!gpdisp_hi16_howto) | |
433 | gpdisp_hi16_howto = bfd_reloc_type_lookup (stdoutput, | |
434 | fixp->fx_r_type); | |
435 | reloc->howto = gpdisp_hi16_howto; | |
436 | } | |
437 | else | |
438 | reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); | |
439 | assert (reloc->howto != 0); | |
440 | if (!fixp->fx_pcrel != !reloc->howto->pc_relative) | |
441 | { | |
ade614d5 KR |
442 | as_fatal ("internal error? cannot generate `%s' relocation", |
443 | bfd_get_reloc_code_name (fixp->fx_r_type)); | |
5749c497 KR |
444 | } |
445 | assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); | |
446 | ||
30869211 KR |
447 | if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL) |
448 | { | |
449 | /* fake out bfd_perform_relocation. sigh */ | |
450 | reloc->addend = -alpha_gp_value; | |
451 | } | |
452 | else if (reloc->howto->pc_relative && reloc->howto->pcrel_offset) | |
5749c497 KR |
453 | { |
454 | reloc->addend = fixp->fx_offset - reloc->address; | |
455 | } | |
456 | else | |
457 | reloc->addend = fixp->fx_offset; | |
458 | return reloc; | |
459 | } | |
460 | ||
461 | static void | |
462 | s_base () | |
463 | { | |
464 | if (first_32bit_quadrant) | |
465 | { | |
466 | /* not fatal, but it might not work in the end */ | |
467 | as_warn ("File overrides no-base-register option."); | |
468 | first_32bit_quadrant = 0; | |
469 | } | |
470 | ||
471 | SKIP_WHITESPACE (); | |
472 | if (*input_line_pointer == '$') | |
473 | { /* $rNN form */ | |
474 | input_line_pointer++; | |
475 | if (*input_line_pointer == 'r') | |
476 | input_line_pointer++; | |
477 | } | |
478 | ||
479 | base_register = get_absolute_expression (); | |
480 | if (base_register < 0 || base_register > 31) | |
481 | { | |
482 | base_register = GP; | |
a2a1a548 | 483 | as_warn ("Bad base register, using $%d.", base_register); |
5749c497 KR |
484 | } |
485 | demand_empty_rest_of_line (); | |
486 | } | |
487 | ||
71f9b3c0 | 488 | static int in_range_signed (val, nbits) |
aaeee550 | 489 | bfd_vma val; |
71f9b3c0 | 490 | int nbits; |
aaeee550 KR |
491 | { |
492 | /* Look at top bit of value that would be stored, figure out how it | |
493 | would be extended by the hardware, and see if that matches the | |
494 | original supplied value. */ | |
495 | bfd_vma mask; | |
496 | bfd_vma one = 1; | |
497 | bfd_vma top_bit, stored_value, missing_bits; | |
498 | ||
499 | mask = (one << nbits) - 1; | |
500 | stored_value = val & mask; | |
265d172e | 501 | top_bit = stored_value & (one << (nbits - 1)); |
aaeee550 | 502 | missing_bits = val & ~mask; |
71f9b3c0 KR |
503 | /* will sign-extend */ |
504 | if (top_bit) | |
aaeee550 | 505 | { |
71f9b3c0 KR |
506 | /* all remaining bits beyond mask should be one */ |
507 | missing_bits |= mask; | |
508 | return missing_bits + 1 == 0; | |
aaeee550 KR |
509 | } |
510 | else | |
511 | { | |
71f9b3c0 KR |
512 | /* all other bits should be zero */ |
513 | return missing_bits == 0; | |
aaeee550 KR |
514 | } |
515 | } | |
516 | ||
71f9b3c0 KR |
517 | #if 0 |
518 | static int in_range_unsigned (val, nbits) | |
519 | bfd_vma val; | |
520 | int nbits; | |
521 | { | |
522 | /* Look at top bit of value that would be stored, figure out how it | |
523 | would be extended by the hardware, and see if that matches the | |
524 | original supplied value. */ | |
525 | bfd_vma mask; | |
526 | bfd_vma one = 1; | |
527 | bfd_vma top_bit, stored_value, missing_bits; | |
528 | ||
529 | mask = (one << nbits) - 1; | |
530 | stored_value = val & mask; | |
531 | top_bit = stored_value & (one << nbits - 1); | |
532 | missing_bits = val & ~mask; | |
533 | return missing_bits == 0; | |
534 | } | |
535 | #endif | |
536 | ||
5749c497 KR |
537 | static void |
538 | s_gprel32 () | |
539 | { | |
540 | expressionS e; | |
541 | char *p; | |
542 | ||
543 | SKIP_WHITESPACE (); | |
544 | expression (&e); | |
545 | switch (e.X_op) | |
546 | { | |
547 | case O_constant: | |
548 | e.X_add_symbol = section_symbol (absolute_section); | |
549 | /* fall through */ | |
550 | case O_symbol: | |
551 | e.X_op = O_subtract; | |
552 | e.X_op_symbol = gp; | |
553 | break; | |
554 | default: | |
555 | abort (); | |
556 | } | |
265d172e ILT |
557 | if (auto_align) |
558 | alpha_align (2, 0, insn_label); | |
5749c497 KR |
559 | p = frag_more (4); |
560 | memset (p, 0, 4); | |
561 | fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &e, 0, | |
562 | BFD_RELOC_GPREL32); | |
265d172e | 563 | insn_label = NULL; |
5749c497 KR |
564 | } |
565 | ||
566 | static void | |
40cd35ff KR |
567 | create_literal_section (secp, name) |
568 | segT *secp; | |
569 | const char *name; | |
5749c497 KR |
570 | { |
571 | segT current_section = now_seg; | |
572 | int current_subsec = now_subseg; | |
40cd35ff | 573 | segT new_sec; |
5749c497 | 574 | |
40cd35ff | 575 | *secp = new_sec = subseg_new (name, 0); |
5749c497 | 576 | subseg_set (current_section, current_subsec); |
40cd35ff KR |
577 | bfd_set_section_alignment (stdoutput, new_sec, 3); |
578 | bfd_set_section_flags (stdoutput, new_sec, | |
5749c497 KR |
579 | SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY |
580 | | SEC_DATA); | |
40cd35ff KR |
581 | } |
582 | ||
40cd35ff KR |
583 | static valueT |
584 | get_lit8_offset (val) | |
585 | bfd_vma val; | |
586 | { | |
587 | valueT retval; | |
588 | if (lit8_sec == 0) | |
589 | { | |
590 | create_literal_section (&lit8_sec, ".lit8"); | |
591 | lit8_sym = section_symbol (lit8_sec); | |
592 | } | |
593 | retval = add_to_literal_pool ((symbolS *) 0, val, lit8_sec, 8); | |
594 | if (retval >= 0xfff0) | |
595 | as_fatal ("overflow in fp literal (.lit8) table"); | |
596 | return retval; | |
597 | } | |
598 | ||
599 | static valueT | |
600 | get_lit4_offset (val) | |
601 | bfd_vma val; | |
602 | { | |
603 | valueT retval; | |
604 | if (lit4_sec == 0) | |
605 | { | |
606 | create_literal_section (&lit4_sec, ".lit4"); | |
607 | lit4_sym = section_symbol (lit4_sec); | |
608 | } | |
609 | retval = add_to_literal_pool ((symbolS *) 0, val, lit4_sec, 4); | |
610 | if (retval >= 0xfff0) | |
611 | as_fatal ("overflow in fp literal (.lit4) table"); | |
612 | return retval; | |
5749c497 KR |
613 | } |
614 | ||
50c551d0 | 615 | static struct alpha_it clear_insn; |
5749c497 | 616 | |
50c551d0 KR |
617 | /* This function is called once, at assembler startup time. It should |
618 | set up all the tables, etc. that the MD part of the assembler will | |
619 | need, that can be determined before arguments are parsed. */ | |
620 | void | |
621 | md_begin () | |
0952861c | 622 | { |
50c551d0 KR |
623 | const char *retval, *name; |
624 | unsigned int i = 0; | |
0952861c | 625 | |
50c551d0 | 626 | op_hash = hash_new (); |
0952861c | 627 | |
50c551d0 KR |
628 | for (i = 0; i < NUMOPCODES; ) |
629 | { | |
630 | const char *name = alpha_opcodes[i].name; | |
631 | retval = hash_insert (op_hash, name, (PTR) &alpha_opcodes[i]); | |
5749c497 | 632 | if (retval) |
0952861c | 633 | as_fatal ("internal error: can't hash opcode `%s': %s", |
50c551d0 | 634 | name, retval); |
0952861c | 635 | |
5749c497 | 636 | do |
50c551d0 KR |
637 | i++; |
638 | while (i < NUMOPCODES | |
639 | && (alpha_opcodes[i].name == name | |
640 | || !strcmp (alpha_opcodes[i].name, name))); | |
5749c497 KR |
641 | } |
642 | /* Some opcodes include modifiers of various sorts with a "/mod" | |
643 | syntax, like the architecture documentation suggests. However, | |
644 | for use with gcc at least, we also need to access those same | |
645 | opcodes without the "/". */ | |
50c551d0 | 646 | for (i = 0; i < NUMOPCODES; ) |
5749c497 | 647 | { |
50c551d0 | 648 | name = alpha_opcodes[i].name; |
0952861c | 649 | |
5749c497 KR |
650 | if (strchr (name, '/')) |
651 | { | |
50c551d0 KR |
652 | char *p = xmalloc (strlen (name)); |
653 | const char *q = name; | |
654 | char *q2 = p; | |
655 | ||
656 | for (; *q; q++) | |
265d172e | 657 | if (*q != '/') |
50c551d0 KR |
658 | *q2++ = *q; |
659 | ||
660 | *q2++ = 0; | |
661 | retval = hash_insert (op_hash, p, (PTR) &alpha_opcodes[i]); | |
0952861c KR |
662 | /* Ignore failures -- the opcode table does duplicate some |
663 | variants in different forms, like "hw_stq" and "hw_st/q". | |
50c551d0 KR |
664 | Maybe the variants can be eliminated, and this error |
665 | checking restored. */ | |
5749c497 | 666 | } |
0952861c | 667 | |
5749c497 | 668 | do |
50c551d0 KR |
669 | i++; |
670 | while (i < NUMOPCODES | |
671 | && (alpha_opcodes[i].name == name | |
672 | || !strcmp (alpha_opcodes[i].name, name))); | |
0952861c | 673 | } |
5749c497 KR |
674 | |
675 | lituse_basereg.X_op = O_constant; | |
676 | lituse_basereg.X_add_number = 1; | |
677 | lituse_byteoff.X_op = O_constant; | |
678 | lituse_byteoff.X_add_number = 2; | |
679 | lituse_jsr.X_op = O_constant; | |
680 | lituse_jsr.X_add_number = 3; | |
681 | ||
682 | /* So .sbss will get used for tiny objects. */ | |
683 | bfd_set_gp_size (stdoutput, 8); | |
71f9b3c0 | 684 | create_literal_section (&lita_sec, ".lita"); |
5749c497 KR |
685 | /* For handling the GP, create a symbol that won't be output in the |
686 | symbol table. We'll edit it out of relocs later. */ | |
fd4f335c | 687 | gp = symbol_create ("<GP value>", lita_sec, 0x8000, &zero_address_frag); |
aaeee550 KR |
688 | |
689 | memset (&clear_insn, 0, sizeof (clear_insn)); | |
690 | for (i = 0; i < MAX_RELOCS; i++) | |
691 | clear_insn.reloc[i].code = BFD_RELOC_NONE; | |
5749c497 KR |
692 | } |
693 | ||
694 | int optnum = 1; | |
695 | ||
0952861c KR |
696 | static void |
697 | emit_insn (insn) | |
698 | struct alpha_it *insn; | |
699 | { | |
700 | char *toP; | |
701 | int j; | |
702 | ||
703 | toP = frag_more (4); | |
704 | ||
705 | /* put out the opcode */ | |
706 | md_number_to_chars (toP, insn->opcode, 4); | |
707 | ||
708 | /* put out the symbol-dependent stuff */ | |
709 | for (j = 0; j < MAX_RELOCS; j++) | |
710 | { | |
711 | struct reloc_data *r = &insn->reloc[j]; | |
712 | fixS *f; | |
713 | ||
714 | if (r->code != BFD_RELOC_NONE) | |
715 | { | |
716 | if (r->exp.X_op == O_constant) | |
717 | { | |
718 | r->exp.X_add_symbol = section_symbol (absolute_section); | |
719 | r->exp.X_op = O_symbol; | |
720 | } | |
721 | f = fix_new_exp (frag_now, (toP - frag_now->fr_literal), 4, | |
722 | &r->exp, r->pcrel, r->code); | |
265d172e ILT |
723 | if (r->code == BFD_RELOC_ALPHA_GPDISP_LO16) |
724 | { | |
725 | static bit_fixS cookie; | |
726 | /* @@ This'll make the range checking in write.c shut up. */ | |
727 | f->fx_bit_fixP = &cookie; | |
728 | } | |
0952861c KR |
729 | } |
730 | } | |
265d172e ILT |
731 | |
732 | insn_label = NULL; | |
0952861c KR |
733 | } |
734 | ||
5749c497 KR |
735 | void |
736 | md_assemble (str) | |
737 | char *str; | |
738 | { | |
0952861c | 739 | int i, count; |
5749c497 KR |
740 | #define MAX_INSNS 5 |
741 | struct alpha_it insns[MAX_INSNS]; | |
742 | ||
743 | count = alpha_ip (str, insns); | |
744 | if (count <= 0) | |
745 | return; | |
746 | ||
747 | for (i = 0; i < count; i++) | |
0952861c | 748 | emit_insn (&insns[i]); |
5749c497 KR |
749 | } |
750 | ||
40cd35ff KR |
751 | static inline void |
752 | maybe_set_gp (sec) | |
753 | asection *sec; | |
754 | { | |
755 | bfd_vma vma; | |
756 | if (!sec) | |
757 | return; | |
758 | vma = bfd_get_section_vma (foo, sec); | |
759 | if (vma && vma < alpha_gp_value) | |
760 | alpha_gp_value = vma; | |
761 | } | |
762 | ||
5749c497 KR |
763 | static void |
764 | select_gp_value () | |
765 | { | |
c79e67a3 KR |
766 | if (alpha_gp_value != 0) |
767 | abort (); | |
768 | ||
40cd35ff KR |
769 | /* Get minus-one in whatever width... */ |
770 | alpha_gp_value = 0; alpha_gp_value--; | |
771 | ||
772 | /* Select the smallest VMA of these existing sections. */ | |
773 | maybe_set_gp (lita_sec); | |
774 | /* maybe_set_gp (sdata); Was disabled before -- should we use it? */ | |
5749c497 | 775 | #if 0 |
40cd35ff KR |
776 | maybe_set_gp (lit8_sec); |
777 | maybe_set_gp (lit4_sec); | |
5749c497 | 778 | #endif |
5749c497 | 779 | |
c79e67a3 | 780 | alpha_gp_value += GP_ADJUSTMENT; |
5749c497 | 781 | |
c79e67a3 | 782 | S_SET_VALUE (gp, alpha_gp_value); |
5749c497 KR |
783 | |
784 | #ifdef DEBUG1 | |
c79e67a3 | 785 | printf ("Chose GP value of %lx\n", alpha_gp_value); |
5749c497 | 786 | #endif |
5749c497 KR |
787 | } |
788 | ||
789 | int | |
790 | alpha_force_relocation (f) | |
791 | fixS *f; | |
792 | { | |
793 | switch (f->fx_r_type) | |
794 | { | |
795 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
796 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
797 | case BFD_RELOC_ALPHA_LITERAL: | |
798 | case BFD_RELOC_ALPHA_LITUSE: | |
799 | case BFD_RELOC_GPREL32: | |
800 | return 1; | |
801 | case BFD_RELOC_ALPHA_HINT: | |
802 | case BFD_RELOC_64: | |
803 | case BFD_RELOC_32: | |
804 | case BFD_RELOC_16: | |
805 | case BFD_RELOC_8: | |
806 | case BFD_RELOC_23_PCREL_S2: | |
807 | case BFD_RELOC_14: | |
0952861c | 808 | case BFD_RELOC_26: |
5749c497 KR |
809 | return 0; |
810 | default: | |
811 | abort (); | |
812 | return 0; | |
813 | } | |
814 | } | |
815 | ||
816 | int | |
817 | alpha_fix_adjustable (f) | |
818 | fixS *f; | |
819 | { | |
820 | /* Are there any relocation types for which we must generate a reloc | |
821 | but we can adjust the values contained within it? */ | |
822 | switch (f->fx_r_type) | |
823 | { | |
824 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
825 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
826 | return 0; | |
827 | case BFD_RELOC_GPREL32: | |
828 | return 1; | |
a2a1a548 ILT |
829 | default: |
830 | return !alpha_force_relocation (f); | |
5749c497 | 831 | } |
a2a1a548 | 832 | /*NOTREACHED*/ |
5749c497 KR |
833 | } |
834 | ||
4a6e1a39 | 835 | valueT |
5749c497 KR |
836 | md_section_align (seg, size) |
837 | segT seg; | |
4a6e1a39 | 838 | valueT size; |
5749c497 KR |
839 | { |
840 | #ifdef OBJ_ECOFF | |
841 | /* This should probably be handled within BFD, or by pulling the | |
842 | number from BFD at least. */ | |
843 | #define MIN 15 | |
844 | size += MIN; | |
845 | size &= ~MIN; | |
846 | #endif | |
847 | return size; | |
848 | } | |
849 | ||
850 | /* Add this thing to the .lita section and produce a LITERAL reloc referring | |
0952861c | 851 | to it. */ |
5749c497 | 852 | |
0952861c KR |
853 | /* Are we currently eligible to emit a LITUSE reloc for the literal |
854 | references just generated? */ | |
855 | static int lituse_pending; | |
5749c497 KR |
856 | |
857 | static void | |
858 | load_symbol_address (reg, insn) | |
859 | int reg; | |
860 | struct alpha_it *insn; | |
861 | { | |
862 | static symbolS *lita_sym; | |
863 | ||
864 | int x; | |
5749c497 | 865 | valueT retval; |
5749c497 KR |
866 | |
867 | if (!lita_sym) | |
868 | { | |
869 | lita_sym = section_symbol (lita_sec); | |
870 | S_CLEAR_EXTERNAL (lita_sym); | |
871 | } | |
872 | ||
873 | retval = add_to_literal_pool (insn->reloc[0].exp.X_add_symbol, | |
874 | insn->reloc[0].exp.X_add_number, | |
875 | lita_sec, 8); | |
876 | ||
5749c497 KR |
877 | /* Now emit a LITERAL relocation for the original section. */ |
878 | insn->reloc[0].exp.X_op = O_symbol; | |
879 | insn->reloc[0].exp.X_add_symbol = lita_sym; | |
880 | insn->reloc[0].exp.X_add_number = retval; | |
881 | insn->reloc[0].code = BFD_RELOC_ALPHA_LITERAL; | |
0952861c | 882 | lituse_pending = 1; |
5749c497 KR |
883 | |
884 | if (retval == 0x8000) | |
885 | /* Overflow? */ | |
886 | as_fatal ("overflow in literal (.lita) table"); | |
887 | x = retval; | |
cf272f02 KR |
888 | if (addr32) |
889 | insn->opcode = (0xa0000000 /* ldl */ | |
890 | | (reg << SA) | |
891 | | (base_register << SB) | |
892 | | (x & 0xffff)); | |
893 | else | |
894 | insn->opcode = (0xa4000000 /* ldq */ | |
895 | | (reg << SA) | |
896 | | (base_register << SB) | |
897 | | (x & 0xffff)); | |
5749c497 KR |
898 | note_gpreg (base_register); |
899 | } | |
900 | ||
901 | /* To load an address with a single instruction, | |
902 | emit a LITERAL reloc in this section, and a REFQUAD | |
903 | for the .lita section, so that we'll be able to access | |
904 | it via $gp: | |
905 | lda REG, xx -> ldq REG, -32752(gp) | |
906 | lda REG, xx+4 -> ldq REG, -32752(gp) | |
907 | lda REG, 4(REG) | |
908 | ||
909 | The offsets need to start near -0x8000, and the generated LITERAL | |
910 | relocations should negate the offset. I don't completely grok the | |
911 | scheme yet. */ | |
912 | ||
913 | static int | |
914 | load_expression (reg, insn) | |
915 | int reg; | |
916 | struct alpha_it *insn; | |
917 | { | |
a2a1a548 | 918 | valueT addend, addendhi, addendlo; |
5749c497 KR |
919 | int num_insns = 1; |
920 | ||
40cd35ff KR |
921 | if (insn->reloc[0].exp.X_add_symbol->bsym->flags & BSF_SECTION_SYM) |
922 | { | |
923 | addend = 0; | |
924 | } | |
925 | else | |
926 | { | |
927 | addend = insn->reloc[0].exp.X_add_number; | |
928 | insn->reloc[0].exp.X_add_number = 0; | |
929 | } | |
5749c497 KR |
930 | load_symbol_address (reg, insn); |
931 | if (addend) | |
932 | { | |
a2a1a548 ILT |
933 | if ((addend & ~0x7fffffff) != 0 |
934 | && (addend & ~0x7fffffff) + 0x80000000 != 0) | |
935 | { | |
936 | as_bad ("assembler not prepared to handle constants >32 bits yet"); | |
937 | addend = 0; | |
938 | } | |
939 | addendlo = addend & 0xffff; | |
940 | addend -= addendlo; | |
941 | addendhi = addend >> 16; | |
942 | if (addendlo & 0x8000) | |
943 | addendhi++; | |
944 | /* It appears that the BASEREG LITUSE reloc should not be used on | |
945 | an LDAH instruction. */ | |
946 | if (addendlo) | |
947 | { | |
948 | insn[1].opcode = (0x20000000 /* lda */ | |
949 | | (reg << SA) | |
950 | | (reg << SB) | |
951 | | (addendlo & 0xffff)); | |
952 | insn[1].reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
953 | insn[1].reloc[0].exp = lituse_basereg; | |
954 | num_insns++; | |
955 | } | |
956 | if (addendhi) | |
957 | { | |
958 | insn[num_insns].opcode = (0x24000000 | |
959 | | (reg << SA) | |
960 | | (reg << SB) | |
961 | | (addendhi & 0xffff)); | |
962 | num_insns++; | |
963 | } | |
964 | if (num_insns == 1) | |
965 | abort (); | |
0952861c | 966 | lituse_pending = 0; |
5749c497 KR |
967 | } |
968 | return num_insns; | |
969 | } | |
970 | ||
c79e67a3 | 971 | static inline void |
5749c497 KR |
972 | getExpression (str, this_insn) |
973 | char *str; | |
974 | struct alpha_it *this_insn; | |
975 | { | |
976 | char *save_in; | |
977 | segT seg; | |
978 | ||
979 | #if 0 /* Not converted to bfd yet, and I don't think we need them | |
980 | for ECOFF. Re-adding a.out support will probably require | |
981 | them though. */ | |
982 | static const struct am { | |
983 | char *name; | |
984 | bfd_reloc_code_real_type reloc; | |
985 | } macro[] = { | |
986 | { "hi", RELOC_48_63 }, | |
987 | { "lo", RELOC_0_15 }, | |
988 | { "ml", RELOC_16_31 }, | |
989 | { "mh", RELOC_32_47 }, | |
990 | { "uhi", RELOC_U_48_63 }, | |
991 | { "uml", RELOC_U_16_31 }, | |
992 | { "umh", RELOC_U_32_47 }, | |
993 | { 0, } | |
994 | }; | |
995 | ||
996 | /* Handle macros: "%macroname(expr)" */ | |
997 | if (*str == '%') | |
998 | { | |
999 | struct am *m; | |
1000 | char *p, *q; | |
1001 | ||
1002 | str++; | |
1003 | m = ¯o[0]; | |
1004 | while (q = m->name) | |
1005 | { | |
1006 | p = str; | |
1007 | while (*q && *p == *q) | |
1008 | p++, q++; | |
1009 | if (*q == 0) | |
1010 | break; | |
1011 | m++; | |
1012 | } | |
1013 | if (q) | |
1014 | { | |
1015 | str = p; /* keep the '(' */ | |
1016 | this_insn->reloc = m->reloc; | |
1017 | } | |
1018 | } | |
1019 | #endif | |
1020 | ||
1021 | save_in = input_line_pointer; | |
1022 | input_line_pointer = str; | |
1023 | ||
1024 | seg = expression (&this_insn->reloc[0].exp); | |
1025 | /* XXX validate seg and exp, make sure they're reasonable */ | |
1026 | expr_end = input_line_pointer; | |
1027 | input_line_pointer = save_in; | |
5749c497 KR |
1028 | } |
1029 | ||
0952861c KR |
1030 | static void |
1031 | emit_unaligned_io (dir, addr_reg, addr_offset, reg) | |
1032 | char *dir; | |
1033 | int addr_reg, reg; | |
1034 | valueT addr_offset; | |
1035 | { | |
1036 | char buf[90]; | |
1037 | sprintf (buf, "%sq_u $%d,%ld($%d)", dir, reg, (long) addr_offset, addr_reg); | |
1038 | md_assemble (buf); | |
1039 | } | |
1040 | ||
1041 | static void | |
1042 | emit_load_unal (addr_reg, addr_offset, reg) | |
1043 | int addr_reg, reg; | |
1044 | valueT addr_offset; | |
1045 | { | |
1046 | emit_unaligned_io ("ld", addr_reg, addr_offset, reg); | |
1047 | } | |
1048 | ||
1049 | static void | |
1050 | emit_store_unal (addr_reg, addr_offset, reg) | |
1051 | int addr_reg, reg; | |
1052 | valueT addr_offset; | |
1053 | { | |
1054 | emit_unaligned_io ("st", addr_reg, addr_offset, reg); | |
1055 | } | |
1056 | ||
1057 | static void | |
1058 | emit_byte_manip_r (op, in, mask, out, mode, which) | |
1059 | char *op; | |
a2a1a548 | 1060 | int in, mask, out, mode, which; |
0952861c KR |
1061 | { |
1062 | char buf[90]; | |
1063 | sprintf (buf, "%s%c%c $%d,$%d,$%d", op, mode, which, in, mask, out); | |
1064 | md_assemble (buf); | |
1065 | } | |
1066 | ||
1067 | static void | |
1068 | emit_extract_r (in, mask, out, mode, which) | |
a2a1a548 | 1069 | int in, mask, out, mode, which; |
0952861c KR |
1070 | { |
1071 | emit_byte_manip_r ("ext", in, mask, out, mode, which); | |
1072 | } | |
1073 | ||
1074 | static void | |
1075 | emit_insert_r (in, mask, out, mode, which) | |
a2a1a548 | 1076 | int in, mask, out, mode, which; |
0952861c KR |
1077 | { |
1078 | emit_byte_manip_r ("ins", in, mask, out, mode, which); | |
1079 | } | |
1080 | ||
1081 | static void | |
1082 | emit_mask_r (in, mask, out, mode, which) | |
a2a1a548 | 1083 | int in, mask, out, mode, which; |
0952861c KR |
1084 | { |
1085 | emit_byte_manip_r ("msk", in, mask, out, mode, which); | |
1086 | } | |
1087 | ||
1088 | static void | |
1089 | emit_sign_extend (reg, size) | |
a2a1a548 | 1090 | int reg, size; |
0952861c KR |
1091 | { |
1092 | char buf[90]; | |
1093 | sprintf (buf, "sll $%d,0x%x,$%d", reg, 64 - size, reg); | |
1094 | md_assemble (buf); | |
1095 | sprintf (buf, "sra $%d,0x%x,$%d", reg, 64 - size, reg); | |
1096 | md_assemble (buf); | |
1097 | } | |
1098 | ||
1099 | static void | |
1100 | emit_bis_r (in1, in2, out) | |
a2a1a548 | 1101 | int in1, in2, out; |
0952861c KR |
1102 | { |
1103 | char buf[90]; | |
1104 | sprintf (buf, "bis $%d,$%d,$%d", in1, in2, out); | |
1105 | md_assemble (buf); | |
1106 | } | |
1107 | ||
aaeee550 KR |
1108 | static int |
1109 | build_mem (opc, ra, rb, disp) | |
1110 | int opc, ra, rb; | |
1111 | bfd_signed_vma disp; | |
1112 | { | |
aaeee550 KR |
1113 | if ((disp >> 15) != 0 |
1114 | && (disp >> 15) + 1 != 0) | |
1115 | abort (); | |
1116 | return ((opc << 26) | (ra << SA) | (rb << SB) | (disp & 0xffff)); | |
1117 | } | |
1118 | ||
1119 | static int | |
1120 | build_operate_n (opc, fn, ra, lit, rc) | |
1121 | int opc, fn, ra, rc; | |
1122 | int lit; | |
1123 | { | |
1124 | if (lit & ~0xff) | |
1125 | abort (); | |
1126 | return ((opc << 26) | (fn << 5) | (ra << SA) | (lit << SN) | (1 << 12) | (rc << SC)); | |
1127 | } | |
1128 | ||
1129 | static void | |
1130 | emit_sll_n (dest, disp, src) | |
1131 | int dest, disp, src; | |
1132 | { | |
1133 | struct alpha_it insn = clear_insn; | |
1134 | insn.opcode = build_operate_n (0x12, 0x39, src, disp, dest); | |
1135 | emit_insn (&insn); | |
1136 | } | |
1137 | ||
1138 | static void | |
1139 | emit_ldah_num (dest, addend, src) | |
1140 | int dest, src; | |
1141 | bfd_vma addend; | |
1142 | { | |
1143 | struct alpha_it insn = clear_insn; | |
1144 | insn.opcode = build_mem (0x09, dest, src, addend); | |
1145 | emit_insn (&insn); | |
1146 | } | |
1147 | ||
1148 | static void | |
1149 | emit_addq_r (in1, in2, out) | |
1150 | int in1, in2, out; | |
1151 | { | |
1152 | struct alpha_it insn = clear_insn; | |
1153 | insn.opcode = 0x40000400 | (in1 << SA) | (in2 << SB) | (out << SC); | |
1154 | emit_insn (&insn); | |
1155 | } | |
1156 | ||
1157 | static void | |
1158 | emit_lda_n (dest, addend, src) | |
1159 | int dest, src; | |
1160 | bfd_vma addend; | |
1161 | { | |
1162 | struct alpha_it insn = clear_insn; | |
1163 | insn.opcode = build_mem (0x08, dest, src, addend); | |
1164 | emit_insn (&insn); | |
1165 | } | |
1166 | ||
1167 | static void | |
1168 | emit_add64 (in, out, num) | |
1169 | int in, out; | |
1170 | bfd_vma num; | |
1171 | { | |
1172 | bfd_signed_vma snum = num; | |
1173 | ||
71f9b3c0 | 1174 | if (in_range_signed (num, 16)) |
aaeee550 KR |
1175 | { |
1176 | emit_lda_n (out, num, in); | |
1177 | return; | |
1178 | } | |
1179 | if ((num & 0xffff) == 0 | |
1180 | && in == ZERO | |
71f9b3c0 | 1181 | && in_range_signed (snum >> 16, 16)) |
aaeee550 KR |
1182 | { |
1183 | emit_ldah_num (out, snum >> 16, in); | |
1184 | return; | |
1185 | } | |
ade614d5 | 1186 | /* I'm not sure this one is getting invoked when it could. */ |
aaeee550 KR |
1187 | if ((num & 1) == 0 && in == ZERO) |
1188 | { | |
71f9b3c0 | 1189 | if (in_range_signed (snum >> 1, 16)) |
aaeee550 KR |
1190 | { |
1191 | emit_lda_n (out, snum >> 1, in); | |
1192 | emit_addq_r (out, out, out); | |
1193 | return; | |
1194 | } | |
1195 | else if (num & 0x1fffe == 0 | |
71f9b3c0 | 1196 | && in_range_signed (snum >> 17, 16)) |
aaeee550 KR |
1197 | { |
1198 | emit_ldah_num (out, snum >> 17, in); | |
1199 | emit_addq_r (out, out, out); | |
1200 | return; | |
1201 | } | |
1202 | } | |
71f9b3c0 | 1203 | if (in_range_signed (num, 32)) |
aaeee550 KR |
1204 | { |
1205 | bfd_vma lo = num & 0xffff; | |
1206 | if (lo & 0x8000) | |
1207 | lo -= 0x10000; | |
1208 | num -= lo; | |
1209 | emit_ldah_num (out, snum >> 16, in); | |
1210 | if (lo) | |
1211 | emit_lda_n (out, lo, out); | |
1212 | return; | |
1213 | } | |
1214 | ||
1215 | if (in != ZERO && in != AT && out != AT && at_ok) | |
1216 | { | |
1217 | emit_add64 (ZERO, AT, num); | |
1218 | emit_addq_r (AT, in, out); | |
1219 | return; | |
1220 | } | |
1221 | ||
1222 | if (in != ZERO) | |
1223 | as_bad ("load expression too complex to expand"); | |
1224 | ||
1225 | /* Could check also for loading 16- or 32-bit value and shifting by | |
1226 | arbitrary displacement. */ | |
1227 | ||
1228 | { | |
1229 | bfd_vma lo = snum & 0xffffffff; | |
1230 | if (lo & 0x80000000) | |
1231 | lo -= ((bfd_vma)0x10000000 << 4); | |
1232 | snum -= lo; | |
aaeee550 KR |
1233 | emit_add64 (ZERO, out, snum >> 32); |
1234 | emit_sll_n (out, 32, out); | |
1235 | if (lo != 0) | |
1236 | emit_add64 (out, out, lo); | |
1237 | } | |
1238 | } | |
1239 | ||
5749c497 KR |
1240 | static int |
1241 | alpha_ip (str, insns) | |
1242 | char *str; | |
1243 | struct alpha_it insns[]; | |
1244 | { | |
1245 | char *s; | |
1246 | const char *args; | |
1247 | char c; | |
1248 | unsigned long i; | |
1249 | struct alpha_opcode *pattern; | |
1250 | char *argsStart; | |
1251 | unsigned int opcode; | |
265d172e | 1252 | unsigned int mask = 0; |
5749c497 KR |
1253 | int match = 0, num_gen = 1; |
1254 | int comma = 0; | |
265d172e ILT |
1255 | int do_add64, add64_in = 0, add64_out = 0; |
1256 | bfd_vma add64_addend = 0; | |
5749c497 KR |
1257 | |
1258 | for (s = str; | |
1259 | islower (*s) || *s == '_' || *s == '/' || *s == '4' || *s == '8'; | |
1260 | ++s) | |
1261 | ; | |
1262 | switch (*s) | |
1263 | { | |
1264 | ||
1265 | case '\0': | |
1266 | break; | |
1267 | ||
1268 | case ',': | |
1269 | comma = 1; | |
1270 | ||
1271 | /*FALLTHROUGH*/ | |
1272 | ||
1273 | case ' ': | |
1274 | *s++ = '\0'; | |
1275 | break; | |
1276 | ||
1277 | default: | |
3a443b1e | 1278 | as_fatal ("Unknown opcode: `%s'", str); |
5749c497 KR |
1279 | } |
1280 | if ((pattern = (struct alpha_opcode *) hash_find (op_hash, str)) == NULL) | |
1281 | { | |
71f9b3c0 | 1282 | as_bad ("Unknown opcode: `%s'", str); |
5749c497 KR |
1283 | return -1; |
1284 | } | |
1285 | if (comma) | |
1286 | *--s = ','; | |
1287 | ||
1288 | argsStart = s; | |
1289 | for (;;) | |
1290 | { | |
71f9b3c0 | 1291 | do_add64 = 0; |
5749c497 KR |
1292 | opcode = pattern->match; |
1293 | num_gen = 1; | |
aaeee550 KR |
1294 | for (i = 0; i < MAX_INSNS; i++) |
1295 | insns[i] = clear_insn; | |
5749c497 KR |
1296 | |
1297 | /* Build the opcode, checking as we go to make sure that the | |
1298 | operands match. */ | |
1299 | for (args = pattern->args;; ++args) | |
1300 | { | |
1301 | switch (*args) | |
1302 | { | |
1303 | ||
1304 | case '\0': /* end of args */ | |
1305 | if (*s == '\0') | |
1306 | { | |
1307 | match = 1; | |
1308 | } | |
1309 | break; | |
1310 | ||
1311 | case '+': | |
1312 | if (*s == '+') | |
1313 | { | |
1314 | ++s; | |
1315 | continue; | |
1316 | } | |
1317 | if (*s == '-') | |
1318 | { | |
1319 | continue; | |
1320 | } | |
1321 | break; | |
1322 | ||
1323 | case '(': /* these must match exactly */ | |
1324 | case ')': | |
1325 | case ',': | |
1326 | case ' ': | |
1327 | case '0': | |
1328 | if (*s++ == *args) | |
1329 | continue; | |
1330 | break; | |
1331 | ||
1332 | case '1': /* next operand must be a register */ | |
1333 | case '2': | |
1334 | case '3': | |
1335 | case 'r': | |
1336 | case 'R': | |
1337 | if (*s++ == '$') | |
1338 | { | |
1339 | switch (c = *s++) | |
1340 | { | |
1341 | ||
1342 | case 'a': /* $at: as temporary */ | |
1343 | if (*s++ != 't') | |
1344 | goto error; | |
1345 | mask = AT; | |
1346 | break; | |
1347 | ||
1348 | case 'g': /* $gp: base register */ | |
1349 | if (*s++ != 'p') | |
1350 | goto error; | |
1351 | mask = base_register; | |
1352 | break; | |
1353 | ||
1354 | case 's': /* $sp: stack pointer */ | |
1355 | if (*s++ != 'p') | |
1356 | goto error; | |
1357 | mask = SP; | |
1358 | break; | |
1359 | ||
1360 | ||
1361 | case 'r': /* any register */ | |
1362 | if (!isdigit (c = *s++)) | |
1363 | { | |
1364 | goto error; | |
1365 | } | |
1366 | /* FALLTHROUGH */ | |
1367 | case '0': | |
1368 | case '1': | |
1369 | case '2': | |
1370 | case '3': | |
1371 | case '4': | |
1372 | case '5': | |
1373 | case '6': | |
1374 | case '7': | |
1375 | case '8': | |
1376 | case '9': | |
1377 | if (isdigit (*s)) | |
1378 | { | |
1379 | if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) | |
1380 | { | |
1381 | goto error; | |
1382 | } | |
1383 | } | |
1384 | else | |
1385 | { | |
1386 | c -= '0'; | |
1387 | } | |
1388 | if ((c == GP) && first_32bit_quadrant) | |
1389 | c = ZERO; | |
1390 | ||
1391 | mask = c; | |
1392 | break; | |
1393 | ||
1394 | default: | |
1395 | goto error; | |
1396 | } | |
1397 | note_gpreg (mask); | |
1398 | /* Got the register, now figure out where it goes in | |
1399 | the opcode. */ | |
1400 | doregister: | |
1401 | switch (*args) | |
1402 | { | |
1403 | ||
1404 | case '1': | |
1405 | case 'e': | |
1406 | opcode |= mask << SA; | |
1407 | continue; | |
1408 | ||
1409 | case '2': | |
1410 | case 'f': | |
1411 | opcode |= mask << SB; | |
1412 | continue; | |
1413 | ||
1414 | case '3': | |
1415 | case 'g': | |
1416 | opcode |= mask; | |
1417 | continue; | |
1418 | ||
1419 | case 'r': | |
1420 | opcode |= (mask << SA) | mask; | |
1421 | continue; | |
1422 | ||
1423 | case 'R': /* ra and rb are the same */ | |
1424 | opcode |= (mask << SA) | (mask << SB); | |
1425 | continue; | |
1426 | ||
1427 | case 'E': | |
1428 | opcode |= (mask << SA) | (mask << SB) | (mask); | |
1429 | continue; | |
1430 | } | |
1431 | } | |
1432 | break; | |
1433 | ||
1434 | case 'e': /* next operand is a floating point register */ | |
1435 | case 'f': | |
1436 | case 'g': | |
1437 | case 'E': | |
1438 | if (*s++ == '$' && *s++ == 'f' && isdigit (*s)) | |
1439 | { | |
1440 | mask = *s++; | |
1441 | if (isdigit (*s)) | |
1442 | { | |
1443 | mask = 10 * (mask - '0') + (*s++ - '0'); | |
1444 | if (mask >= 32) | |
1445 | { | |
1446 | break; | |
1447 | } | |
1448 | } | |
1449 | else | |
1450 | { | |
1451 | mask -= '0'; | |
1452 | } | |
1453 | note_fpreg (mask); | |
1454 | /* same encoding as gp registers */ | |
1455 | goto doregister; | |
1456 | } | |
1457 | break; | |
1458 | ||
1459 | #if 0 | |
1460 | case 'h': /* bits 16..31 */ | |
1461 | insns[0].reloc = RELOC_16_31; | |
1462 | goto immediate; | |
1463 | #endif | |
1464 | ||
1465 | case 'l': /* bits 0..15 */ | |
1466 | insns[0].reloc[0].code = BFD_RELOC_16; | |
1467 | goto immediate; | |
1468 | ||
1469 | case 'L': /* 21 bit PC relative immediate */ | |
1470 | insns[0].reloc[0].code = BFD_RELOC_23_PCREL_S2; | |
1471 | insns[0].reloc[0].pcrel = 1; | |
1472 | goto immediate; | |
1473 | ||
1474 | case 'i': /* 14 bit immediate */ | |
1475 | if (OPCODE (opcode) != 0x1a) | |
1476 | /* Not a jmp variant?? */ | |
1477 | abort (); | |
1478 | else if (opcode & 0x8000) | |
1479 | /* ret or jsr_coroutine */ | |
1480 | { | |
1481 | insns[0].reloc[0].code = BFD_RELOC_14; | |
1482 | insns[0].reloc[0].pcrel = 0; | |
1483 | } | |
1484 | else | |
1485 | /* jmp or jsr */ | |
1486 | { | |
1487 | insns[0].reloc[0].code = BFD_RELOC_ALPHA_HINT; | |
1488 | insns[0].reloc[0].pcrel = 1; | |
1489 | } | |
1490 | goto immediate; | |
1491 | ||
1492 | case 'b': /* 8 bit immediate */ | |
1493 | insns[0].reloc[0].code = BFD_RELOC_8; | |
1494 | goto immediate; | |
1495 | ||
0952861c KR |
1496 | case 'I': /* 26 bit immediate, for PALcode */ |
1497 | insns[0].reloc[0].code = BFD_RELOC_26; | |
1498 | goto immediate; | |
1499 | ||
71f9b3c0 KR |
1500 | case 't': /* 12 bit displacement, for PALcode */ |
1501 | insns[0].reloc[0].code = BFD_RELOC_12_PCREL; | |
5749c497 KR |
1502 | goto immediate; |
1503 | ||
1504 | case '8': /* 8 bit 0...7 */ | |
71f9b3c0 | 1505 | insns[0].reloc[0].code = BFD_RELOC_8; |
5749c497 KR |
1506 | goto immediate; |
1507 | ||
5749c497 KR |
1508 | immediate: |
1509 | if (*s == ' ') | |
1510 | s++; | |
c79e67a3 | 1511 | getExpression (s, &insns[0]); |
5749c497 KR |
1512 | s = expr_end; |
1513 | /* Handle overflow in certain instructions by converting | |
1514 | to other instructions. */ | |
1515 | if (insns[0].reloc[0].code == BFD_RELOC_8 | |
1516 | && insns[0].reloc[0].exp.X_op == O_constant | |
1517 | && (insns[0].reloc[0].exp.X_add_number < 0 | |
1518 | || insns[0].reloc[0].exp.X_add_number > 0xff)) | |
1519 | { | |
1520 | if (OPCODE (opcode) == 0x10 | |
1521 | && (OP_FCN (opcode) == 0x00 /* addl */ | |
1522 | || OP_FCN (opcode) == 0x40 /* addl/v */ | |
1523 | || OP_FCN (opcode) == 0x20 /* addq */ | |
1524 | || OP_FCN (opcode) == 0x60 /* addq/v */ | |
1525 | || OP_FCN (opcode) == 0x09 /* subl */ | |
1526 | || OP_FCN (opcode) == 0x49 /* subl/v */ | |
1527 | || OP_FCN (opcode) == 0x29 /* subq */ | |
1528 | || OP_FCN (opcode) == 0x69 /* subq/v */ | |
1529 | || OP_FCN (opcode) == 0x02 /* s4addl */ | |
1530 | || OP_FCN (opcode) == 0x22 /* s4addq */ | |
1531 | || OP_FCN (opcode) == 0x0b /* s4subl */ | |
1532 | || OP_FCN (opcode) == 0x2b /* s4subq */ | |
1533 | || OP_FCN (opcode) == 0x12 /* s8addl */ | |
1534 | || OP_FCN (opcode) == 0x32 /* s8addq */ | |
1535 | || OP_FCN (opcode) == 0x1b /* s8subl */ | |
1536 | || OP_FCN (opcode) == 0x3b /* s8subq */ | |
1537 | ) | |
1538 | /* Can we make it fit by negating? */ | |
1539 | && -insns[0].reloc[0].exp.X_add_number < 0xff | |
1540 | && -insns[0].reloc[0].exp.X_add_number > 0) | |
1541 | { | |
1542 | opcode ^= 0x120; /* convert add<=>sub */ | |
1543 | insns[0].reloc[0].exp.X_add_number *= -1; | |
1544 | } | |
1545 | else if (at_ok && macro_ok) | |
1546 | { | |
1547 | /* Constant value supplied, but it's too large. */ | |
71f9b3c0 KR |
1548 | do_add64 = 1; |
1549 | add64_in = ZERO; | |
1550 | add64_out = AT; | |
1551 | add64_addend = insns[0].reloc[0].exp.X_add_number; | |
aaeee550 KR |
1552 | opcode &= ~ 0x1000; |
1553 | opcode |= (AT << SB); | |
5749c497 KR |
1554 | insns[0].reloc[0].code = BFD_RELOC_NONE; |
1555 | } | |
1556 | else | |
1557 | as_bad ("overflow in 8-bit literal field in `operate' format insn"); | |
1558 | } | |
aaeee550 KR |
1559 | else if (insns[0].reloc[0].code == BFD_RELOC_16 |
1560 | && insns[0].reloc[0].exp.X_op == O_constant | |
71f9b3c0 KR |
1561 | && !in_range_signed (insns[0].reloc[0].exp.X_add_number, |
1562 | 16)) | |
aaeee550 KR |
1563 | { |
1564 | bfd_vma val = insns[0].reloc[0].exp.X_add_number; | |
1565 | if (OPCODE (opcode) == 0x08) | |
1566 | { | |
71f9b3c0 KR |
1567 | do_add64 = 1; |
1568 | add64_in = ZERO; | |
1569 | add64_out = AT; | |
1570 | add64_addend = val; | |
aaeee550 KR |
1571 | opcode &= ~0x1000; |
1572 | opcode |= (AT << SB); | |
1573 | insns[0].reloc[0].code = BFD_RELOC_NONE; | |
1574 | } | |
1575 | else if (OPCODE (opcode) == 0x09 | |
71f9b3c0 | 1576 | && in_range_signed (val >> 16, 16)) |
aaeee550 KR |
1577 | { |
1578 | /* ldah with high operand - convert to low */ | |
1579 | insns[0].reloc[0].exp.X_add_number >>= 16; | |
1580 | } | |
1581 | else | |
1582 | as_bad ("I don't know how to handle 32+ bit constants here yet, sorry."); | |
1583 | } | |
1584 | else if (insns[0].reloc[0].code == BFD_RELOC_32 | |
1585 | && insns[0].reloc[0].exp.X_op == O_constant) | |
1586 | { | |
1587 | bfd_vma val = insns[0].reloc[0].exp.X_add_number; | |
1588 | bfd_signed_vma sval = val; | |
1589 | if (val >> 32 != 0 | |
1590 | && sval >> 32 != 0 | |
1591 | && sval >> 32 != -1) | |
1592 | as_bad ("I don't know how to handle 64 bit constants here yet, sorry."); | |
1593 | } | |
5749c497 KR |
1594 | continue; |
1595 | ||
40cd35ff KR |
1596 | case 'F': |
1597 | { | |
a2a1a548 | 1598 | int format, length, mode, i; |
40cd35ff KR |
1599 | char temp[20 /*MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT*/]; |
1600 | char *err; | |
1601 | static const char formats[4] = "FGfd"; | |
1602 | bfd_vma bits, offset; | |
1603 | char *old_input_line_pointer = input_line_pointer; | |
1604 | ||
1605 | input_line_pointer = s; | |
1606 | SKIP_WHITESPACE (); | |
1607 | memset (temp, 0, sizeof (temp)); | |
1608 | mode = (opcode >> 26) & 3; | |
1609 | format = formats[mode]; | |
1610 | err = md_atof (format, temp, &length); | |
1611 | if (err) | |
1612 | { | |
1613 | as_bad ("Bad floating literal: %s", err); | |
1614 | bits = 0; | |
1615 | } | |
1616 | else | |
1617 | { | |
1618 | /* Generate little-endian number from byte sequence. */ | |
1619 | bits = 0; | |
1620 | for (i = length - 1; i >= 0; i--) | |
1621 | bits += ((bfd_vma)(temp[i] & 0xff)) << (i * 8); | |
1622 | } | |
1623 | switch (length) | |
1624 | { | |
1625 | case 8: | |
1626 | offset = get_lit8_offset (bits) - 0x8000; | |
1627 | insns[0].reloc[0].exp.X_add_symbol = lit8_sym; | |
1628 | insns[0].reloc[0].exp.X_add_number = 0x8000; | |
1629 | break; | |
1630 | case 4: | |
1631 | offset = get_lit4_offset (bits) - 0x8000; | |
1632 | insns[0].reloc[0].exp.X_add_symbol = lit4_sym; | |
1633 | insns[0].reloc[0].exp.X_add_number = 0x8000; | |
1634 | break; | |
1635 | default: | |
1636 | abort (); | |
1637 | } | |
1638 | insns[0].reloc[0].exp.X_op = O_symbol; | |
1639 | offset &= 0xffff; | |
1640 | num_gen = load_expression (AT, &insns[0]); | |
0952861c KR |
1641 | if (lituse_pending) |
1642 | { | |
1643 | insns[num_gen].reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
1644 | insns[num_gen].reloc[0].exp = lituse_basereg; | |
1645 | lituse_pending = 0; | |
1646 | } | |
40cd35ff KR |
1647 | insns[num_gen++].opcode = opcode | (AT << SB) | offset; |
1648 | opcode = insns[0].opcode; | |
1649 | s = input_line_pointer; | |
1650 | input_line_pointer = old_input_line_pointer; | |
1651 | } | |
1652 | continue; | |
1653 | ||
5749c497 KR |
1654 | /* The following two.. take advantage of the fact that |
1655 | opcode already contains most of what we need to know. | |
1656 | We just prepend to the instr an "ldah | |
1657 | $r,%ml(expr)($base)" and turn this one (done later | |
1658 | after we return) into something like "stq | |
1659 | $r,%lo(expr)(at)" or "ldq $r,%lo(expr)($r)". | |
1660 | ||
1661 | NOTE: This can fail later on at link time if the | |
1662 | offset from $base actually turns out to be more than | |
1663 | 2**31 or 2**47 if use_large_offsets is set. */ | |
1664 | case 'P': /* Addressing macros: PUT */ | |
1665 | mask = AT; /* register 'at' */ | |
1666 | /* fall through */ | |
1667 | ||
1668 | case 'G': /* Addressing macros: GET */ | |
5749c497 KR |
1669 | /* All it is missing is the expression, which is what we |
1670 | will get now */ | |
1671 | ||
1672 | if (*s == ' ') | |
1673 | s++; | |
c79e67a3 | 1674 | getExpression (s, &insns[0]); |
5749c497 KR |
1675 | s = expr_end; |
1676 | ||
1677 | /* Must check for "lda ..,number" too */ | |
1678 | if (insns[0].reloc[0].exp.X_op == O_big) | |
1679 | { | |
1680 | as_warn ("Sorry, not yet. Put bignums in .data section yourself."); | |
1681 | return -1; | |
1682 | } | |
1683 | if (insns[0].reloc[0].exp.X_op == O_constant) | |
1684 | { | |
aaeee550 KR |
1685 | bfd_vma val = insns[0].reloc[0].exp.X_add_number; |
1686 | bfd_vma top, low; | |
5749c497 KR |
1687 | |
1688 | insns[0].reloc[0].code = BFD_RELOC_NONE; | |
1689 | insns[1].reloc[0].code = BFD_RELOC_NONE; | |
1690 | ||
aaeee550 KR |
1691 | low = val & 0xffff; |
1692 | if (low & 0x8000) | |
1693 | low -= 0x10000; | |
1694 | top = val - low; | |
1695 | if (top) | |
5749c497 | 1696 | { |
71f9b3c0 KR |
1697 | do_add64 = 1; |
1698 | add64_in = ZERO; | |
1699 | add64_out = AT; | |
1700 | add64_addend = top; | |
aaeee550 | 1701 | opcode |= AT << SB; |
5749c497 KR |
1702 | } |
1703 | else | |
aaeee550 KR |
1704 | opcode |= ZERO << SB; |
1705 | opcode &= ~0x1000; | |
1706 | opcode |= low & 0xffff; | |
5749c497 KR |
1707 | } |
1708 | else if (insns[0].reloc[0].exp.X_op == O_symbol) | |
1709 | { | |
1710 | unsigned long old_opcode = opcode; | |
265d172e | 1711 | int tmp_reg = -1; |
5749c497 KR |
1712 | |
1713 | if (!macro_ok) | |
1714 | as_bad ("insn requires expansion but `nomacro' specified"); | |
1715 | else if (*args == 'G') | |
1716 | tmp_reg = mask; | |
1717 | else if (!at_ok) | |
1718 | as_bad ("insn expansion requires AT use, but `noat' specified"); | |
1719 | else | |
1720 | tmp_reg = AT; | |
1721 | num_gen = load_expression (tmp_reg, insns); | |
1722 | opcode = insns[0].opcode; | |
0952861c KR |
1723 | /* lda is opcode 8, 0x20000000, and the macros that use |
1724 | this code have an opcode field of 0. The latter | |
1725 | require further processing, and we don't have the | |
1726 | true opcode here. */ | |
1727 | if (OPCODE (old_opcode) != 0 | |
1728 | && OPCODE (old_opcode) != 0x08) | |
5749c497 KR |
1729 | { |
1730 | struct alpha_it *i; | |
1731 | i = &insns[num_gen++]; | |
5749c497 | 1732 | i->opcode = old_opcode | (tmp_reg << SB); |
40cd35ff | 1733 | |
0952861c KR |
1734 | if (lituse_pending) |
1735 | { | |
1736 | i->reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
1737 | i->reloc[0].exp = lituse_basereg; | |
1738 | lituse_pending = 0; | |
1739 | } | |
5749c497 KR |
1740 | } |
1741 | } | |
1742 | else | |
1743 | { | |
1744 | /* Not a number */ | |
1745 | num_gen = 2; | |
1746 | insns[1].reloc[0].exp = insns[0].reloc[0].exp; | |
1747 | ||
1748 | /* Generate: ldah REG,x1(GP); OP ?,x0(REG) */ | |
1749 | ||
1750 | abort (); /* relocs need fixing */ | |
1751 | #if 0 | |
1752 | insns[1].reloc = RELOC_0_15; | |
1753 | insns[1].opcode = opcode | mask << SB; | |
1754 | ||
1755 | insns[0].reloc = RELOC_16_31; | |
1756 | opcode = 0x24000000 /*ldah*/ | mask << SA | (base_register << SB); | |
1757 | #endif | |
1758 | } | |
1759 | ||
1760 | continue; | |
1761 | ||
1762 | /* Same failure modes as above, actually most of the | |
40cd35ff | 1763 | same code shared. */ |
5749c497 KR |
1764 | case 'B': /* Builtins */ |
1765 | args++; | |
1766 | switch (*args) | |
1767 | { | |
1768 | ||
1769 | case 'a': /* ldgp */ | |
1770 | ||
1771 | if (first_32bit_quadrant || no_mixed_code) | |
1772 | return -1; | |
1773 | switch (OUTPUT_FLAVOR) | |
1774 | { | |
1775 | case bfd_target_aout_flavour: | |
1776 | /* this is cmu's a.out version */ | |
1777 | insns[0].reloc[0].code = BFD_RELOC_NONE; | |
1778 | /* generate "zap %r,0xf,%r" to take high 32 bits */ | |
1779 | opcode |= 0x48001600 /* zap ?,#,?*/ | (0xf << SN); | |
1780 | break; | |
1781 | case bfd_target_ecoff_flavour: | |
1782 | /* Given "ldgp R1,N(R2)", turn it into something | |
1783 | like "ldah R1,###(R2) ; lda R1,###(R1)" with | |
1784 | appropriate constants and relocations. */ | |
1785 | { | |
1786 | unsigned long r1, r2; | |
1787 | unsigned long addend = 0; | |
1788 | ||
1789 | num_gen = 2; | |
1790 | r2 = mask; | |
1791 | r1 = opcode & 0x3f; | |
1792 | insns[0].reloc[0].code = BFD_RELOC_ALPHA_GPDISP_HI16; | |
1793 | insns[0].reloc[0].pcrel = 1; | |
1794 | insns[0].reloc[0].exp.X_op = O_symbol; | |
1795 | insns[0].reloc[0].exp.X_add_symbol = gp; | |
1796 | insns[0].reloc[0].exp.X_add_number = 0; | |
1797 | insns[0].opcode = (0x24000000 /* ldah */ | |
1798 | | (r1 << SA) | |
1799 | | (r2 << SB)); | |
1800 | insns[1].reloc[0].code = BFD_RELOC_ALPHA_GPDISP_LO16; | |
1801 | insns[1].reloc[0].exp.X_op = O_symbol; | |
1802 | insns[1].reloc[0].exp.X_add_symbol = gp; | |
1803 | insns[1].reloc[0].exp.X_add_number = 4; | |
1804 | insns[1].reloc[0].pcrel = 1; | |
1805 | insns[1].opcode = 0x20000000 | (r1 << SA) | (r1 << SB); | |
1806 | opcode = insns[0].opcode; | |
1807 | /* merge in addend */ | |
1808 | insns[1].opcode |= addend & 0xffff; | |
1809 | insns[0].opcode |= ((addend >> 16) | |
1810 | + (addend & 0x8000 ? 1 : 0)); | |
0952861c KR |
1811 | if (r2 == PV) |
1812 | ecoff_set_gp_prolog_size (0); | |
5749c497 KR |
1813 | } |
1814 | break; | |
1815 | default: | |
1816 | abort (); | |
1817 | } | |
1818 | continue; | |
1819 | ||
1820 | ||
1821 | case 'b': /* setgp */ | |
1822 | switch (OUTPUT_FLAVOR) | |
1823 | { | |
1824 | case bfd_target_aout_flavour: | |
1825 | /* generate "zap %r,0xf,$gp" to take high 32 bits */ | |
1826 | opcode |= 0x48001600 /* zap ?,#,?*/ | |
1827 | | (0xf << SN) | (base_register); | |
1828 | break; | |
1829 | default: | |
1830 | abort (); | |
1831 | } | |
1832 | continue; | |
1833 | ||
1834 | case 'c': /* jsr $r,foo becomes | |
1835 | lda $27,foo | |
1836 | jsr $r,($27),foo | |
1837 | Register 27, t12, is used by convention | |
1838 | here. */ | |
1839 | { | |
1840 | struct alpha_it *jsr; | |
1841 | expressionS etmp; | |
1842 | struct reloc_data *r; | |
1843 | ||
1844 | /* We still have to parse the function name */ | |
1845 | if (*s == ' ') | |
1846 | s++; | |
c79e67a3 | 1847 | getExpression (s, &insns[0]); |
5749c497 KR |
1848 | etmp = insns[0].reloc[0].exp; |
1849 | s = expr_end; | |
1850 | num_gen = load_expression (PV, &insns[0]); | |
1851 | note_gpreg (PV); | |
1852 | ||
1853 | jsr = &insns[num_gen++]; | |
71f9b3c0 | 1854 | jsr->opcode = (pattern->match |
5749c497 KR |
1855 | | (mask << SA) |
1856 | | (PV << SB) | |
1857 | | 0); | |
0952861c | 1858 | if (lituse_pending) |
5749c497 KR |
1859 | { |
1860 | /* LITUSE wasn't emitted yet */ | |
1861 | jsr->reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
1862 | jsr->reloc[0].exp = lituse_jsr; | |
1863 | r = &jsr->reloc[1]; | |
0952861c | 1864 | lituse_pending = 0; |
5749c497 KR |
1865 | } |
1866 | else | |
1867 | r = &jsr->reloc[0]; | |
1868 | r->exp = etmp; | |
1869 | r->code = BFD_RELOC_ALPHA_HINT; | |
1870 | r->pcrel = 1; | |
1871 | opcode = insns[0].opcode; | |
1872 | } | |
1873 | continue; | |
1874 | ||
0952861c KR |
1875 | case 'd': |
1876 | /* Sub-word loads and stores. We load the address into | |
1877 | $at, which might involve using the `P' parameter | |
1878 | processing too, then emit a sequence to get the job | |
1879 | done, using unaligned memory accesses and byte | |
1880 | manipulation, with t9 and t10 as temporaries. */ | |
1881 | { | |
1882 | /* Characteristics of access. */ | |
265d172e | 1883 | int is_load = 99, is_unsigned = 0, is_unaligned = 0; |
0952861c KR |
1884 | int mode_size, mode; |
1885 | /* Register operand. */ | |
265d172e | 1886 | int reg = -1; |
0952861c KR |
1887 | /* Addend for loads and stores. */ |
1888 | valueT addend; | |
1889 | /* Which register do we use for the address? */ | |
1890 | int addr; | |
1891 | ||
1892 | { | |
1893 | /* Pick apart name and set flags. */ | |
a2a1a548 | 1894 | const char *s = pattern->name; |
0952861c KR |
1895 | |
1896 | if (*s == 'u') | |
1897 | { | |
1898 | is_unaligned = 1; | |
1899 | s++; | |
1900 | } | |
1901 | ||
1902 | if (s[0] == 'l' && s[1] == 'd') | |
1903 | is_load = 1; | |
1904 | else if (s[0] == 's' && s[1] == 't') | |
1905 | is_load = 0; | |
1906 | else | |
1907 | as_fatal ("unrecognized sub-word access insn `%s'", | |
1908 | str); | |
1909 | s += 2; | |
1910 | ||
1911 | mode = *s++; | |
1912 | if (mode == 'b') mode_size = 1; | |
1913 | else if (mode == 'w') mode_size = 2; | |
1914 | else if (mode == 'l') mode_size = 4; | |
1915 | else if (mode == 'q') mode_size = 8; | |
1916 | else abort (); | |
1917 | ||
1918 | if (*s == 'u') | |
1919 | { | |
1920 | is_unsigned = 1; | |
1921 | s++; | |
1922 | } | |
1923 | ||
1924 | assert (*s == 0); | |
1925 | ||
1926 | /* Longwords are always kept sign-extended. */ | |
1927 | if (mode == 'l' && is_unsigned) | |
1928 | abort (); | |
1929 | /* There's no special unaligned byte handling. */ | |
1930 | if (mode == 'b' && is_unaligned) | |
1931 | abort (); | |
1932 | /* Stores don't care about signedness. */ | |
1933 | if (!is_load && is_unsigned) | |
1934 | abort (); | |
1935 | } | |
1936 | ||
1937 | if (args[-2] == 'P') | |
1938 | { | |
1939 | addr = AT; | |
1940 | addend = 0; | |
1941 | } | |
1942 | else | |
1943 | { | |
1944 | /* foo r1,num(r2) | |
1945 | r2 -> mask | |
1946 | r1 -> (opcode >> SA) & 31 | |
1947 | num -> insns->reloc[0].* | |
1948 | ||
1949 | We want to emit "lda at,num(r2)", since these | |
1950 | operations require the use of a single register | |
1951 | with the starting address of the memory operand | |
1952 | we want to access. | |
1953 | ||
1954 | We could probably get away without doing this | |
1955 | (and use r2 below, with the addend for the | |
1956 | actual reads and writes) in cases where the | |
1957 | addend is known to be a multiple of 8. */ | |
1958 | int r2 = mask; | |
1959 | int r1 = (opcode >> SA) & 31; | |
1960 | ||
1961 | if (insns[0].reloc[0].code == BFD_RELOC_NONE) | |
1962 | addend = 0; | |
1963 | else if (insns[0].reloc[0].code == BFD_RELOC_16) | |
1964 | { | |
1965 | if (insns[0].reloc[0].exp.X_op != O_constant) | |
1966 | abort (); | |
1967 | addend = insns[0].reloc[0].exp.X_add_number; | |
1968 | } | |
1969 | else | |
1970 | abort (); | |
1971 | ||
1972 | if (addend + mode_size - 1 < 0x7fff | |
1973 | && (addend % 8) == 0 | |
1974 | && (r2 < T9 || r2 > T12)) | |
1975 | { | |
1976 | addr = r2; | |
1977 | num_gen = 0; | |
1978 | } | |
1979 | else | |
1980 | { | |
1981 | /* Let later relocation processing deal | |
1982 | with the addend field. */ | |
1983 | insns[num_gen-1].opcode = (0x20000000 /* lda */ | |
1984 | | (AT << SA) | |
1985 | | (r2 << SB)); | |
1986 | addr = AT; | |
1987 | addend = 0; | |
1988 | } | |
1989 | reg = r1; | |
1990 | } | |
1991 | ||
1992 | /* Because the emit_* routines append directly to | |
1993 | the current frag, we now need to flush any | |
1994 | pending insns. */ | |
1995 | { | |
1996 | int i; | |
1997 | for (i = 0; i < num_gen; i++) | |
1998 | emit_insn (&insns[i]); | |
1999 | num_gen = 0; | |
2000 | } | |
2001 | ||
2002 | if (is_load) | |
2003 | { | |
265d172e | 2004 | int reg2, reg3 = -1; |
0952861c KR |
2005 | |
2006 | if (is_unaligned) | |
2007 | reg2 = T9, reg3 = T10; | |
2008 | else | |
2009 | reg2 = reg; | |
2010 | ||
2011 | emit_load_unal (addr, addend, T9); | |
2012 | if (is_unaligned) | |
2013 | emit_load_unal (addr, addend + mode_size - 1, T10); | |
2014 | emit_extract_r (T9, addr, reg2, mode, 'l'); | |
2015 | if (is_unaligned) | |
2016 | { | |
2017 | emit_extract_r (T10, addr, reg3, mode, 'h'); | |
2018 | emit_bis_r (T9, T10, reg); | |
2019 | } | |
2020 | if (!is_unsigned) | |
2021 | emit_sign_extend (reg, mode_size * 8); | |
2022 | } | |
2023 | else | |
2024 | { | |
2025 | /* The second word gets processed first | |
2026 | because if the address does turn out to be | |
2027 | aligned, the processing for the second word | |
2028 | will be pushing around all-zeros, and the | |
2029 | entire value will be handled as the `first' | |
2030 | word. So we want to store the `first' word | |
2031 | last. */ | |
2032 | /* Pair these up so that the memory loads get | |
2033 | separated from each other, as well as being | |
2034 | well in advance of the uses of the values | |
2035 | loaded. */ | |
2036 | if (is_unaligned) | |
2037 | { | |
2038 | emit_load_unal (addr, addend + mode_size - 1, T11); | |
2039 | emit_insert_r (reg, addr, T12, mode, 'h'); | |
2040 | } | |
2041 | emit_load_unal (addr, addend, T9); | |
2042 | emit_insert_r (reg, addr, T10, mode, 'l'); | |
2043 | if (is_unaligned) | |
2044 | emit_mask_r (T12, addr, T12, mode, 'h'); | |
2045 | emit_mask_r (T10, addr, T10, mode, 'l'); | |
2046 | if (is_unaligned) | |
2047 | emit_bis_r (T11, T12, T11); | |
2048 | emit_bis_r (T9, T10, T9); | |
2049 | if (is_unaligned) | |
2050 | emit_store_unal (addr, addend + mode_size - 1, T11); | |
2051 | emit_store_unal (addr, addend, T9); | |
2052 | } | |
2053 | } | |
2054 | return 0; | |
2055 | ||
5749c497 KR |
2056 | /* DIVISION and MODULUS. Yech. |
2057 | Convert OP x,y,result | |
2058 | to mov x,t10 | |
2059 | mov y,t11 | |
2060 | jsr t9, __OP | |
2061 | mov t12,result | |
2062 | ||
2063 | with appropriate optimizations if t10,t11,t12 | |
2064 | are the registers specified by the compiler. | |
2065 | We are missing an obvious optimization | |
2066 | opportunity here; if the ldq generated by the | |
2067 | jsr assembly requires a cycle or two to make | |
2068 | the value available, initiating it before one | |
2069 | or two of the mov instructions would result in | |
2070 | faster execution. */ | |
2071 | case '0': /* reml */ | |
2072 | case '1': /* divl */ | |
2073 | case '2': /* remq */ | |
2074 | case '3': /* divq */ | |
2075 | case '4': /* remlu */ | |
2076 | case '5': /* divlu */ | |
2077 | case '6': /* remqu */ | |
2078 | case '7': /* divqu */ | |
2079 | { | |
2080 | static char func[8][6] = { | |
2081 | "reml", "divl", "remq", "divq", | |
2082 | "remlu", "divlu", "remqu", "divqu" | |
2083 | }; | |
2084 | char expansion[64]; | |
2085 | int reg; | |
2086 | ||
2087 | /* All regs parsed, in opcode */ | |
2088 | ||
2089 | /* Do the expansions, one instr at a time */ | |
2090 | ||
2091 | reg = (opcode >> SA) & 31; | |
2092 | if (reg != T10) | |
2093 | { | |
2094 | /* x->t10 */ | |
2095 | sprintf (expansion, "mov $%d,$%d", reg, T10); | |
2096 | md_assemble (expansion); | |
2097 | } | |
2098 | reg = (opcode >> SB) & 31; | |
2099 | if (reg == T10) | |
2100 | /* we already overwrote it! */ | |
2101 | abort (); | |
2102 | else if (reg != T11) | |
2103 | { | |
2104 | /* y->t11 */ | |
2105 | sprintf (expansion, "mov $%d,$%d", reg, T11); | |
2106 | md_assemble (expansion); | |
2107 | } | |
2108 | sprintf (expansion, "lda $%d,__%s", PV, func[*args - '0']); | |
2109 | md_assemble (expansion); | |
2110 | sprintf (expansion, "jsr $%d,($%d),__%s", T9, PV, | |
2111 | func[*args - '0']); | |
2112 | md_assemble (expansion); | |
2113 | #if 0 /* huh? */ | |
2114 | if (!first_32bit_quadrant) | |
2115 | { | |
2116 | sprintf (expansion, | |
2117 | "zap $%d,0xf,$%d", | |
2118 | T9, base_register); | |
2119 | md_assemble (expansion); | |
2120 | } | |
2121 | #endif | |
2122 | sprintf (expansion, "ldgp $%d,0($%d)", | |
2123 | base_register, T9); | |
2124 | md_assemble (expansion); | |
2125 | ||
2126 | /* Use insns[0] to get at the result */ | |
2127 | if ((reg = (opcode & 31)) != PV) | |
2128 | opcode = (0x47e00400 /* or zero,zero,zero */ | |
2129 | | (PV << SB) | |
2130 | | reg /* Rc */ ); /* pv->z */ | |
2131 | else | |
2132 | num_gen = 0; | |
2133 | } | |
2134 | continue; | |
2135 | } | |
2136 | /* fall through */ | |
2137 | ||
2138 | default: | |
2139 | abort (); | |
2140 | } | |
2141 | break; | |
2142 | } | |
2143 | error: | |
2144 | if (match == 0) | |
2145 | { | |
2146 | /* Args don't match. */ | |
2147 | if (&pattern[1] - alpha_opcodes < NUMOPCODES | |
2148 | && !strcmp (pattern->name, pattern[1].name)) | |
2149 | { | |
2150 | ++pattern; | |
2151 | s = argsStart; | |
2152 | continue; | |
2153 | } | |
2154 | else | |
2155 | { | |
2156 | as_warn ("Illegal operands"); | |
2157 | return -1; | |
2158 | } | |
2159 | } | |
2160 | else | |
2161 | { | |
2162 | /* Args match, see if a float instructions and -nofloats */ | |
2163 | if (nofloats && pattern->isa_float) | |
2164 | return -1; | |
2165 | } | |
2166 | break; | |
2167 | } | |
2168 | ||
71f9b3c0 KR |
2169 | if (do_add64) |
2170 | { | |
2171 | emit_add64 (add64_in, add64_out, add64_addend); | |
2172 | } | |
2173 | ||
5749c497 KR |
2174 | insns[0].opcode = opcode; |
2175 | return num_gen; | |
2176 | } | |
2177 | ||
2178 | /* Turn a string in input_line_pointer into a floating point constant | |
2179 | of type type, and store the appropriate bytes in *litP. The number | |
2180 | of LITTLENUMS emitted is stored in *sizeP. An error message is | |
2181 | returned, or NULL on OK. */ | |
2182 | ||
2183 | /* Equal to MAX_PRECISION in atof-ieee.c */ | |
2184 | #define MAX_LITTLENUMS 6 | |
2185 | ||
2186 | char * | |
2187 | md_atof (type, litP, sizeP) | |
2188 | char type; | |
2189 | char *litP; | |
2190 | int *sizeP; | |
2191 | { | |
2192 | int prec; | |
2193 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
2194 | LITTLENUM_TYPE *wordP; | |
2195 | char *t; | |
2196 | char *atof_ieee (), *vax_md_atof (); | |
2197 | ||
2198 | switch (type) | |
2199 | { | |
2200 | /* VAX floats */ | |
2201 | case 'G': | |
c79e67a3 | 2202 | /* VAX md_atof doesn't like "G" for some reason. */ |
5749c497 KR |
2203 | type = 'g'; |
2204 | case 'F': | |
2205 | case 'D': | |
2206 | return vax_md_atof (type, litP, sizeP); | |
2207 | ||
2208 | /* IEEE floats */ | |
2209 | case 'f': | |
2210 | prec = 2; | |
2211 | break; | |
2212 | ||
2213 | case 'd': | |
2214 | prec = 4; | |
2215 | break; | |
2216 | ||
2217 | case 'x': | |
2218 | case 'X': | |
2219 | prec = 6; | |
2220 | break; | |
2221 | ||
2222 | case 'p': | |
2223 | case 'P': | |
2224 | prec = 6; | |
2225 | break; | |
2226 | ||
2227 | default: | |
2228 | *sizeP = 0; | |
2229 | return "Bad call to MD_ATOF()"; | |
2230 | } | |
2231 | t = atof_ieee (input_line_pointer, type, words); | |
2232 | if (t) | |
2233 | input_line_pointer = t; | |
2234 | *sizeP = prec * sizeof (LITTLENUM_TYPE); | |
2235 | ||
2236 | for (wordP = words + prec - 1; prec--;) | |
2237 | { | |
2238 | md_number_to_chars (litP, (long) (*wordP--), sizeof (LITTLENUM_TYPE)); | |
2239 | litP += sizeof (LITTLENUM_TYPE); | |
2240 | } | |
2241 | ||
2242 | return 0; | |
2243 | } | |
2244 | ||
2245 | void | |
2246 | md_bignum_to_chars (buf, bignum, nchars) | |
2247 | char *buf; | |
2248 | LITTLENUM_TYPE *bignum; | |
2249 | int nchars; | |
2250 | { | |
2251 | while (nchars) | |
2252 | { | |
2253 | LITTLENUM_TYPE work = *bignum++; | |
2254 | int nb = CHARS_PER_LITTLENUM; | |
2255 | ||
2256 | do | |
2257 | { | |
2258 | *buf++ = work & ((1 << BITS_PER_CHAR) - 1); | |
2259 | if (--nchars == 0) | |
2260 | return; | |
2261 | work >>= BITS_PER_CHAR; | |
2262 | } | |
2263 | while (--nb); | |
2264 | } | |
2265 | } | |
f3d817d8 DM |
2266 | \f |
2267 | CONST char *md_shortopts = "Fm:"; | |
2268 | struct option md_longopts[] = { | |
2269 | #define OPTION_32ADDR (OPTION_MD_BASE) | |
2270 | {"32addr", no_argument, NULL, OPTION_32ADDR}, | |
2271 | {NULL, no_argument, NULL, 0} | |
2272 | }; | |
2273 | size_t md_longopts_size = sizeof(md_longopts); | |
5749c497 KR |
2274 | |
2275 | int | |
f3d817d8 DM |
2276 | md_parse_option (c, arg) |
2277 | int c; | |
2278 | char *arg; | |
5749c497 | 2279 | { |
f3d817d8 | 2280 | switch (c) |
5749c497 | 2281 | { |
f3d817d8 | 2282 | case 'F': |
5749c497 | 2283 | nofloats = 1; |
f3d817d8 DM |
2284 | break; |
2285 | ||
2286 | case OPTION_32ADDR: | |
cf272f02 | 2287 | addr32 = 1; |
f3d817d8 | 2288 | break; |
f3d817d8 DM |
2289 | |
2290 | default: | |
2291 | return 0; | |
5749c497 | 2292 | } |
f3d817d8 DM |
2293 | |
2294 | return 1; | |
5749c497 KR |
2295 | } |
2296 | ||
f3d817d8 DM |
2297 | void |
2298 | md_show_usage (stream) | |
2299 | FILE *stream; | |
2300 | { | |
2301 | fprintf(stream, "\ | |
2302 | Alpha options:\n\ | |
2303 | -32addr treat addresses as 32-bit values\n\ | |
2304 | -F lack floating point instructions support\n\ | |
2305 | -m21064 | -m21066 | -m21164\n\ | |
a2a1a548 | 2306 | specify variant of Alpha architecture\n"); |
f3d817d8 DM |
2307 | } |
2308 | \f | |
5749c497 KR |
2309 | static void |
2310 | s_proc (is_static) | |
a2a1a548 | 2311 | int is_static; |
5749c497 KR |
2312 | { |
2313 | /* XXXX Align to cache linesize XXXXX */ | |
2314 | char *name; | |
2315 | char c; | |
2316 | char *p; | |
2317 | symbolS *symbolP; | |
2318 | int temp; | |
2319 | ||
2320 | /* Takes ".proc name,nargs" */ | |
2321 | name = input_line_pointer; | |
2322 | c = get_symbol_end (); | |
2323 | p = input_line_pointer; | |
2324 | symbolP = symbol_find_or_make (name); | |
2325 | *p = c; | |
2326 | SKIP_WHITESPACE (); | |
2327 | if (*input_line_pointer != ',') | |
2328 | { | |
2329 | *p = 0; | |
2330 | as_warn ("Expected comma after name \"%s\"", name); | |
2331 | *p = c; | |
2332 | temp = 0; | |
2333 | ignore_rest_of_line (); | |
2334 | } | |
2335 | else | |
2336 | { | |
2337 | input_line_pointer++; | |
2338 | temp = get_absolute_expression (); | |
2339 | } | |
2340 | /* symbolP->sy_other = (signed char) temp; */ | |
2341 | as_warn ("unhandled: .proc %s,%d", name, temp); | |
2342 | demand_empty_rest_of_line (); | |
2343 | } | |
2344 | ||
2345 | static void | |
2346 | s_alpha_set (x) | |
2347 | int x; | |
2348 | { | |
2349 | char *name = input_line_pointer, ch, *s; | |
2350 | int yesno = 1; | |
2351 | ||
2352 | while (!is_end_of_line[(unsigned char) *input_line_pointer]) | |
2353 | input_line_pointer++; | |
2354 | ch = *input_line_pointer; | |
2355 | *input_line_pointer = '\0'; | |
2356 | ||
2357 | s = name; | |
2358 | if (s[0] == 'n' && s[1] == 'o') | |
2359 | { | |
2360 | yesno = 0; | |
2361 | s += 2; | |
2362 | } | |
2363 | if (!strcmp ("reorder", s)) | |
2364 | /* ignore */ ; | |
2365 | else if (!strcmp ("at", s)) | |
2366 | at_ok = yesno; | |
2367 | else if (!strcmp ("macro", s)) | |
2368 | macro_ok = yesno; | |
3a443b1e C |
2369 | else if (!strcmp ("move", s)) |
2370 | /* ignore */ ; | |
2371 | else if (!strcmp ("volatile", s)) | |
2372 | /* ignore */ ; | |
5749c497 | 2373 | else |
71f9b3c0 | 2374 | as_warn ("Tried to .set unrecognized mode `%s'", name); |
5749c497 KR |
2375 | *input_line_pointer = ch; |
2376 | demand_empty_rest_of_line (); | |
2377 | } | |
2378 | ||
2379 | /* @@ Is this right?? */ | |
2380 | long | |
2381 | md_pcrel_from (fixP) | |
2382 | fixS *fixP; | |
2383 | { | |
2384 | valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; | |
2385 | switch (fixP->fx_r_type) | |
2386 | { | |
2387 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
2388 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
2389 | return addr; | |
2390 | default: | |
2391 | return fixP->fx_size + addr; | |
2392 | } | |
2393 | } | |
2394 | ||
265d172e ILT |
2395 | /* Handle the .align pseudo-op. This aligns to a power of two. It |
2396 | also adjusts any current instruction label. We treat this the same | |
2397 | way the MIPS port does: .align 0 turns off auto alignment. */ | |
2398 | ||
2399 | static void | |
2400 | s_alpha_align (ignore) | |
2401 | int ignore; | |
2402 | { | |
2403 | register int temp; | |
2404 | register long temp_fill; | |
2405 | long max_alignment = 15; | |
2406 | ||
2407 | temp = get_absolute_expression (); | |
2408 | if (temp > max_alignment) | |
2409 | as_bad ("Alignment too large: %d. assumed.", temp = max_alignment); | |
2410 | else if (temp < 0) | |
2411 | { | |
2412 | as_warn ("Alignment negative: 0 assumed."); | |
2413 | temp = 0; | |
2414 | } | |
2415 | if (*input_line_pointer == ',') | |
2416 | { | |
2417 | input_line_pointer++; | |
2418 | temp_fill = get_absolute_expression (); | |
2419 | } | |
2420 | else | |
2421 | temp_fill = 0; | |
2422 | if (temp) | |
2423 | { | |
2424 | auto_align = 1; | |
2425 | alpha_align (temp, (int) temp_fill, insn_label); | |
2426 | } | |
2427 | else | |
2428 | { | |
2429 | auto_align = 0; | |
2430 | } | |
2431 | ||
2432 | demand_empty_rest_of_line (); | |
2433 | } | |
2434 | ||
2435 | static void | |
2436 | alpha_align (n, fill, label) | |
5749c497 | 2437 | int n; |
265d172e ILT |
2438 | int fill; |
2439 | symbolS *label; | |
5749c497 | 2440 | { |
265d172e | 2441 | if (fill == 0 |
5749c497 KR |
2442 | && (now_seg == text_section |
2443 | || !strcmp (now_seg->name, ".init") | |
2444 | || !strcmp (now_seg->name, ".fini"))) | |
2445 | { | |
4a6e1a39 | 2446 | static const unsigned char nop_pattern[] = { 0x1f, 0x04, 0xff, 0x47 }; |
5749c497 | 2447 | frag_align_pattern (n, nop_pattern, sizeof (nop_pattern)); |
5749c497 | 2448 | } |
265d172e ILT |
2449 | else |
2450 | frag_align (n, fill); | |
2451 | ||
2452 | if (label != NULL) | |
2453 | { | |
2454 | assert (S_GET_SEGMENT (label) == now_seg); | |
2455 | label->sy_frag = frag_now; | |
2456 | S_SET_VALUE (label, (valueT) frag_now_fix ()); | |
2457 | } | |
2458 | } | |
2459 | ||
2460 | /* This function is called just before the generic pseudo-ops output | |
2461 | something. It just clears insn_label. */ | |
2462 | ||
2463 | void | |
2464 | alpha_flush_pending_output () | |
2465 | { | |
2466 | insn_label = NULL; | |
2467 | } | |
2468 | ||
2469 | /* Handle data allocation pseudo-ops. This is like the generic | |
2470 | version, but it makes sure the current label, if any, is correctly | |
2471 | aligned. */ | |
2472 | ||
2473 | static void | |
2474 | s_alpha_cons (log_size) | |
2475 | int log_size; | |
2476 | { | |
2477 | if (log_size > 0 && auto_align) | |
2478 | alpha_align (log_size, 0, insn_label); | |
2479 | insn_label = NULL; | |
2480 | cons (1 << log_size); | |
2481 | } | |
2482 | ||
2483 | /* Handle floating point allocation pseudo-ops. This is like the | |
2484 | generic vresion, but it makes sure the current label, if any, is | |
2485 | correctly aligned. */ | |
2486 | ||
2487 | static void | |
2488 | s_alpha_float_cons (type) | |
2489 | int type; | |
2490 | { | |
2491 | if (auto_align) | |
2492 | { | |
2493 | int log_size; | |
2494 | ||
2495 | switch (type) | |
2496 | { | |
2497 | default: | |
2498 | case 'f': | |
2499 | case 'F': | |
2500 | log_size = 2; | |
2501 | break; | |
2502 | ||
2503 | case 'd': | |
2504 | case 'D': | |
2505 | case 'G': | |
2506 | log_size = 3; | |
2507 | break; | |
2508 | ||
2509 | case 'x': | |
2510 | case 'X': | |
2511 | case 'p': | |
2512 | case 'P': | |
2513 | log_size = 4; | |
2514 | break; | |
2515 | } | |
2516 | ||
2517 | alpha_align (log_size, 0, insn_label); | |
2518 | } | |
2519 | ||
2520 | insn_label = NULL; | |
2521 | float_cons (type); | |
2522 | } | |
2523 | ||
2524 | /* This function is called whenever a label is defined. It is used to | |
2525 | adjust the label when an automatic alignment occurs. */ | |
2526 | ||
2527 | void | |
2528 | alpha_define_label (sym) | |
2529 | symbolS *sym; | |
2530 | { | |
2531 | insn_label = sym; | |
5749c497 KR |
2532 | } |
2533 | ||
2534 | int | |
2535 | md_apply_fix (fixP, valueP) | |
2536 | fixS *fixP; | |
2537 | valueT *valueP; | |
2538 | { | |
2539 | valueT value; | |
2540 | int size; | |
2541 | valueT addend; | |
2542 | char *p = fixP->fx_frag->fr_literal + fixP->fx_where; | |
2543 | ||
2544 | value = *valueP; | |
2545 | ||
2546 | switch (fixP->fx_r_type) | |
2547 | { | |
2548 | /* The GPDISP relocations are processed internally with a symbol | |
2549 | referring to the current function; we need to drop in a value | |
2550 | which, when added to the address of the start of the function, | |
2551 | gives the desired GP. */ | |
2552 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
2553 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
2554 | addend = value; | |
2555 | if (fixP->fx_r_type == BFD_RELOC_ALPHA_GPDISP_HI16) | |
2556 | { | |
2557 | assert (fixP->fx_next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16); | |
2558 | #ifdef DEBUG1 | |
2559 | printf ("hi16: "); | |
2560 | fprintf_vma (stdout, addend); | |
2561 | printf ("\n"); | |
2562 | #endif | |
2563 | if (addend & 0x8000) | |
2564 | addend += 0x10000; | |
2565 | addend >>= 16; | |
2566 | fixP->fx_offset = 4; /* @@ Compute this using fx_next. */ | |
2567 | } | |
2568 | else | |
2569 | { | |
2570 | #ifdef DEBUG1 | |
2571 | printf ("lo16: "); | |
2572 | fprintf_vma (stdout, addend); | |
2573 | printf ("\n"); | |
2574 | #endif | |
2575 | addend &= 0xffff; | |
2576 | fixP->fx_offset = 0; | |
2577 | } | |
2578 | md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, | |
2579 | addend, 2); | |
2580 | fixP->fx_addsy = section_symbol (absolute_section); | |
2581 | fixP->fx_offset += fixP->fx_frag->fr_address + fixP->fx_where; | |
2582 | break; | |
2583 | ||
2584 | case BFD_RELOC_8: | |
2585 | /* Write 8 bits, shifted left 13 bit positions. */ | |
2586 | value &= 0xff; | |
2587 | p++; | |
2588 | *p &= 0x1f; | |
2589 | *p |= (value << 5) & 0xe0; | |
2590 | value >>= 3; | |
2591 | p++; | |
2592 | *p &= 0xe0; | |
2593 | *p |= value; | |
2594 | value >>= 5; | |
2595 | fixP->fx_done = 1; | |
5749c497 KR |
2596 | if (value != 0) |
2597 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2598 | "overflow in type-%d reloc", (int) fixP->fx_r_type); | |
2599 | return 3; | |
2600 | ||
2601 | case BFD_RELOC_32: | |
30869211 KR |
2602 | size = 4; |
2603 | goto do_it; | |
5749c497 | 2604 | case BFD_RELOC_64: |
30869211 KR |
2605 | size = 8; |
2606 | goto do_it; | |
5749c497 KR |
2607 | case BFD_RELOC_16: |
2608 | /* Don't want overflow checking. */ | |
2609 | size = 2; | |
2610 | do_it: | |
2611 | if (fixP->fx_pcrel == 0 | |
2612 | && fixP->fx_addsy == 0) | |
2613 | { | |
2614 | md_number_to_chars (p, value, size); | |
2615 | /* @@ Overflow checks?? */ | |
2616 | goto done; | |
2617 | } | |
2618 | break; | |
2619 | ||
0952861c KR |
2620 | case BFD_RELOC_26: |
2621 | if (fixP->fx_addsy != 0 | |
2622 | && fixP->fx_addsy->bsym->section != absolute_section) | |
2623 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2624 | "PALcode instructions require immediate constant function code"); | |
2625 | else if (value >> 26 != 0) | |
2626 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2627 | "overflow in 26-bit PALcode function field"); | |
2628 | *p++ = value & 0xff; | |
2629 | value >>= 8; | |
2630 | *p++ = value & 0xff; | |
2631 | value >>= 8; | |
2632 | *p++ = value & 0xff; | |
2633 | value >>= 8; | |
2634 | { | |
2635 | char x = *p; | |
2636 | x &= ~3; | |
2637 | x |= (value & 3); | |
2638 | *p++ = x; | |
2639 | } | |
2640 | goto done; | |
2641 | ||
5749c497 KR |
2642 | case BFD_RELOC_14: |
2643 | if (fixP->fx_addsy != 0 | |
2644 | && fixP->fx_addsy->bsym->section != absolute_section) | |
2645 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2646 | "ret/jsr_coroutine requires constant in displacement field"); | |
2647 | else if (value >> 14 != 0) | |
2648 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2649 | "overflow in 14-bit operand field of ret or jsr_coroutine"); | |
2650 | *p++ = value & 0xff; | |
2651 | value >>= 8; | |
2652 | *p = (*p & 0xc0) | (value & 0x3f); | |
2653 | goto done; | |
2654 | ||
2655 | case BFD_RELOC_23_PCREL_S2: | |
2656 | /* Write 21 bits only. */ | |
2657 | value >>= 2; | |
2658 | *p++ = value & 0xff; | |
2659 | value >>= 8; | |
2660 | *p++ = value & 0xff; | |
2661 | value >>= 8; | |
2662 | *p &= 0xe0; | |
2663 | *p |= (value & 0x1f); | |
2664 | goto done; | |
2665 | ||
71f9b3c0 KR |
2666 | case BFD_RELOC_12_PCREL: |
2667 | *p++ = value & 0xff; | |
2668 | value >>= 8; | |
2669 | *p &= 0xf0; | |
2670 | *p |= (value & 0x0f); | |
2671 | goto done; | |
2672 | ||
5749c497 KR |
2673 | case BFD_RELOC_ALPHA_LITERAL: |
2674 | case BFD_RELOC_ALPHA_LITUSE: | |
2675 | return 2; | |
2676 | ||
2677 | case BFD_RELOC_GPREL32: | |
2678 | assert (fixP->fx_subsy == gp); | |
c79e67a3 | 2679 | value = - alpha_gp_value; /* huh? this works... */ |
5749c497 KR |
2680 | fixP->fx_subsy = 0; |
2681 | md_number_to_chars (p, value, 4); | |
2682 | break; | |
2683 | ||
2684 | case BFD_RELOC_ALPHA_HINT: | |
2685 | if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0) | |
2686 | { | |
2687 | size = 2; | |
2688 | goto do_it; | |
2689 | } | |
2690 | return 2; | |
2691 | ||
2692 | default: | |
71f9b3c0 KR |
2693 | as_fatal ("unhandled relocation type %s", |
2694 | bfd_get_reloc_code_name (fixP->fx_r_type)); | |
5749c497 KR |
2695 | return 9; |
2696 | } | |
2697 | ||
2698 | if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0) | |
2699 | { | |
2700 | printf ("type %d reloc done?\n", fixP->fx_r_type); | |
2701 | done: | |
2702 | fixP->fx_done = 1; | |
2703 | return 42; | |
2704 | } | |
2705 | ||
2706 | return 0x12345678; | |
2707 | } | |
2708 | ||
2709 | void | |
4a6e1a39 | 2710 | alpha_frob_ecoff_data () |
5749c497 | 2711 | { |
c79e67a3 | 2712 | select_gp_value (); |
5749c497 | 2713 | /* $zero and $f31 are read-only */ |
c79e67a3 KR |
2714 | alpha_gprmask &= ~1; |
2715 | alpha_fprmask &= ~1; | |
5749c497 KR |
2716 | } |
2717 | ||
2718 | /* The Alpha has support for some VAX floating point types, as well as for | |
2719 | IEEE floating point. We consider IEEE to be the primary floating point | |
2720 | format, and sneak in the VAX floating point support here. */ | |
2721 | #define md_atof vax_md_atof | |
2722 | #include "config/atof-vax.c" |