]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/config/tc-microblaze.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / tc-microblaze.c
CommitLineData
7ba29e2a
NC
1/* tc-microblaze.c -- Assemble code for Xilinx MicroBlaze
2
fd67aa11 3 Copyright (C) 2009-2024 Free Software Foundation, Inc.
7ba29e2a
NC
4
5 This file is part of GAS, the GNU Assembler.
6
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20 02110-1301, USA. */
21
7ba29e2a 22#include "as.h"
df7b86aa 23#include <stdio.h>
7ba29e2a
NC
24#include "bfd.h"
25#include "subsegs.h"
26#define DEFINE_TABLE
27#include "../opcodes/microblaze-opc.h"
28#include "../opcodes/microblaze-opcm.h"
e23c5ac0 29#include "safe-ctype.h"
7ba29e2a
NC
30#include <string.h>
31#include <dwarf2dbg.h>
32#include "aout/stab_gnu.h"
33
34#ifndef streq
35#define streq(a,b) (strcmp (a, b) == 0)
36#endif
37
f23200ad
ME
38#define OPTION_EB (OPTION_MD_BASE + 0)
39#define OPTION_EL (OPTION_MD_BASE + 1)
40
7ba29e2a 41void microblaze_generate_symbol (char *sym);
5b7c81bd 42static bool check_spl_reg (unsigned *);
7ba29e2a
NC
43
44/* Several places in this file insert raw instructions into the
45 object. They should generate the instruction
46 and then use these four macros to crack the instruction value into
47 the appropriate byte values. */
48#define INST_BYTE0(x) (target_big_endian ? (((x) >> 24) & 0xFF) : ((x) & 0xFF))
49#define INST_BYTE1(x) (target_big_endian ? (((x) >> 16) & 0xFF) : (((x) >> 8) & 0xFF))
50#define INST_BYTE2(x) (target_big_endian ? (((x) >> 8) & 0xFF) : (((x) >> 16) & 0xFF))
51#define INST_BYTE3(x) (target_big_endian ? ((x) & 0xFF) : (((x) >> 24) & 0xFF))
52
53/* This array holds the chars that always start a comment. If the
54 pre-processor is disabled, these aren't very useful. */
55const char comment_chars[] = "#";
56
57const char line_separator_chars[] = ";";
58
59/* This array holds the chars that only start a comment at the beginning of
60 a line. */
61const char line_comment_chars[] = "#";
62
63const int md_reloc_size = 8; /* Size of relocation record. */
64
65/* Chars that can be used to separate mant
66 from exp in floating point numbers. */
67const char EXP_CHARS[] = "eE";
68
69/* Chars that mean this number is a floating point constant
70 As in 0f12.456
71 or 0d1.2345e12. */
72const char FLT_CHARS[] = "rRsSfFdDxXpP";
73
74/* INST_PC_OFFSET and INST_NO_OFFSET are 0 and 1. */
75#define UNDEFINED_PC_OFFSET 2
76#define DEFINED_ABS_SEGMENT 3
77#define DEFINED_PC_OFFSET 4
78#define DEFINED_RO_SEGMENT 5
79#define DEFINED_RW_SEGMENT 6
80#define LARGE_DEFINED_PC_OFFSET 7
81#define GOT_OFFSET 8
82#define PLT_OFFSET 9
83#define GOTOFF_OFFSET 10
69b06cc8
ME
84#define TLSGD_OFFSET 11
85#define TLSLD_OFFSET 12
86#define TLSDTPMOD_OFFSET 13
87#define TLSDTPREL_OFFSET 14
88#define TLSGOTTPREL_OFFSET 15
89#define TLSTPREL_OFFSET 16
3f0a5f17
ME
90#define TEXT_OFFSET 17
91#define TEXT_PC_OFFSET 18
7ba29e2a
NC
92
93/* Initialize the relax table. */
94const relax_typeS md_relax_table[] =
95{
96 { 1, 1, 0, 0 }, /* 0: Unused. */
97 { 1, 1, 0, 0 }, /* 1: Unused. */
98 { 1, 1, 0, 0 }, /* 2: Unused. */
99 { 1, 1, 0, 0 }, /* 3: Unused. */
100 { 32767, -32768, INST_WORD_SIZE, LARGE_DEFINED_PC_OFFSET }, /* 4: DEFINED_PC_OFFSET. */
101 { 1, 1, 0, 0 }, /* 5: Unused. */
102 { 1, 1, 0, 0 }, /* 6: Unused. */
103 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 7: LARGE_DEFINED_PC_OFFSET. */
104 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 8: GOT_OFFSET. */
105 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 9: PLT_OFFSET. */
106 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 10: GOTOFF_OFFSET. */
69b06cc8
ME
107 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 11: TLSGD_OFFSET. */
108 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 12: TLSLD_OFFSET. */
109 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*1, 0 }, /* 13: TLSDTPMOD_OFFSET. */
110 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 14: TLSDTPREL_OFFSET. */
111 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 15: TLSGOTTPREL_OFFSET. */
3f0a5f17
ME
112 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 16: TLSTPREL_OFFSET. */
113 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 17: TEXT_OFFSET. */
114 { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 } /* 18: TEXT_PC_OFFSET. */
7ba29e2a
NC
115};
116
629310ab 117static htab_t opcode_hash_control; /* Opcode mnemonics. */
7ba29e2a
NC
118
119static segT sbss_segment = 0; /* Small bss section. */
120static segT sbss2_segment = 0; /* Section not used. */
121static segT sdata_segment = 0; /* Small data section. */
122static segT sdata2_segment = 0; /* Small read-only section. */
123static segT rodata_segment = 0; /* read-only section. */
124
125/* Generate a symbol for stabs information. */
126
127void
128microblaze_generate_symbol (char *sym)
129{
130#define MICROBLAZE_FAKE_LABEL_NAME "XL0\001"
131 static int microblaze_label_count;
132 sprintf (sym, "%sL%d", MICROBLAZE_FAKE_LABEL_NAME, microblaze_label_count);
133 ++microblaze_label_count;
134}
135
136/* Handle the section changing pseudo-ops. */
137
138static void
139microblaze_s_text (int ignore ATTRIBUTE_UNUSED)
140{
141#ifdef OBJ_ELF
142 obj_elf_text (ignore);
143#else
144 s_text (ignore);
145#endif
146}
147
148static void
149microblaze_s_data (int ignore ATTRIBUTE_UNUSED)
150{
151#ifdef OBJ_ELF
a8c4d40b 152 obj_elf_change_section (".data", SHT_PROGBITS, SHF_ALLOC+SHF_WRITE,
f2711095 153 0, 0, false);
7ba29e2a
NC
154#else
155 s_data (ignore);
156#endif
157}
158
159/* Things in the .sdata segment are always considered to be in the small data section. */
160
161static void
162microblaze_s_sdata (int ignore ATTRIBUTE_UNUSED)
163{
164#ifdef OBJ_ELF
a8c4d40b 165 obj_elf_change_section (".sdata", SHT_PROGBITS, SHF_ALLOC+SHF_WRITE,
f2711095 166 0, 0, false);
7ba29e2a
NC
167#else
168 s_data (ignore);
169#endif
170}
171
172/* Pseudo op to make file scope bss items. */
173
174static void
175microblaze_s_lcomm (int xxx ATTRIBUTE_UNUSED)
176{
177 char *name;
178 char c;
179 char *p;
180 offsetT size;
181 symbolS *symbolP;
182 offsetT align;
7ba29e2a
NC
183 char *pfrag;
184 int align2;
185 segT current_seg = now_seg;
186 subsegT current_subseg = now_subseg;
187
d02603dc 188 c = get_symbol_name (&name);
7ba29e2a
NC
189
190 /* Just after name is now '\0'. */
191 p = input_line_pointer;
d02603dc 192 (void) restore_line_pointer (c);
7ba29e2a
NC
193 SKIP_WHITESPACE ();
194 if (*input_line_pointer != ',')
195 {
196 as_bad (_("Expected comma after symbol-name: rest of line ignored."));
197 ignore_rest_of_line ();
198 return;
199 }
200
201 input_line_pointer++; /* skip ',' */
202 if ((size = get_absolute_expression ()) < 0)
203 {
204 as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size);
205 ignore_rest_of_line ();
206 return;
207 }
208
209 /* The third argument to .lcomm is the alignment. */
210 if (*input_line_pointer != ',')
211 align = 8;
212 else
213 {
214 ++input_line_pointer;
215 align = get_absolute_expression ();
216 if (align <= 0)
217 {
218 as_warn (_("ignoring bad alignment"));
219 align = 8;
220 }
221 }
222
223 *p = 0;
224 symbolP = symbol_find_or_make (name);
225 *p = c;
226
227 if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
228 {
229 as_bad (_("Ignoring attempt to re-define symbol `%s'."),
230 S_GET_NAME (symbolP));
231 ignore_rest_of_line ();
232 return;
233 }
234
235 if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size)
236 {
237 as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."),
238 S_GET_NAME (symbolP),
239 (long) S_GET_VALUE (symbolP),
240 (long) size);
241
242 ignore_rest_of_line ();
243 return;
244 }
245
246 /* Allocate_bss. */
7ba29e2a
NC
247 if (align)
248 {
249 /* Convert to a power of 2 alignment. */
250 for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2);
251 if (align != 1)
252 {
253 as_bad (_("Common alignment not a power of 2"));
254 ignore_rest_of_line ();
255 return;
256 }
257 }
258 else
259 align2 = 0;
260
261 record_alignment (current_seg, align2);
262 subseg_set (current_seg, current_subseg);
263 if (align2)
264 frag_align (align2, 0, 0);
265 if (S_GET_SEGMENT (symbolP) == current_seg)
266 symbol_get_frag (symbolP)->fr_symbol = 0;
267 symbol_set_frag (symbolP, frag_now);
268 pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
269 (char *) 0);
270 *pfrag = 0;
271 S_SET_SIZE (symbolP, size);
272 S_SET_SEGMENT (symbolP, current_seg);
273 subseg_set (current_seg, current_subseg);
274 demand_empty_rest_of_line ();
275}
276
277static void
278microblaze_s_rdata (int localvar)
279{
280#ifdef OBJ_ELF
281 if (localvar == 0)
282 {
283 /* rodata. */
a8c4d40b 284 obj_elf_change_section (".rodata", SHT_PROGBITS, SHF_ALLOC,
f2711095 285 0, 0, false);
7ba29e2a
NC
286 if (rodata_segment == 0)
287 rodata_segment = subseg_new (".rodata", 0);
288 }
289 else
290 {
291 /* 1 .sdata2. */
a8c4d40b 292 obj_elf_change_section (".sdata2", SHT_PROGBITS, SHF_ALLOC,
f2711095 293 0, 0, false);
7ba29e2a
NC
294 }
295#else
296 s_data (ignore);
297#endif
298}
299
300static void
301microblaze_s_bss (int localvar)
302{
303#ifdef OBJ_ELF
304 if (localvar == 0) /* bss. */
a8c4d40b 305 obj_elf_change_section (".bss", SHT_NOBITS, SHF_ALLOC+SHF_WRITE,
f2711095 306 0, 0, false);
7ba29e2a
NC
307 else if (localvar == 1)
308 {
309 /* sbss. */
a8c4d40b 310 obj_elf_change_section (".sbss", SHT_NOBITS, SHF_ALLOC+SHF_WRITE,
f2711095 311 0, 0, false);
7ba29e2a
NC
312 if (sbss_segment == 0)
313 sbss_segment = subseg_new (".sbss", 0);
314 }
315#else
316 s_data (ignore);
317#endif
318}
319
320/* endp_p is always 1 as this func is called only for .end <funcname>
321 This func consumes the <funcname> and calls regular processing
322 s_func(1) with arg 1 (1 for end). */
323
324static void
325microblaze_s_func (int end_p ATTRIBUTE_UNUSED)
326{
d02603dc
NC
327 char *name;
328 restore_line_pointer (get_symbol_name (&name));
7ba29e2a
NC
329 s_func (1);
330}
331
332/* Handle the .weakext pseudo-op as defined in Kane and Heinrich. */
333
334static void
335microblaze_s_weakext (int ignore ATTRIBUTE_UNUSED)
336{
337 char *name;
338 int c;
339 symbolS *symbolP;
340 expressionS exp;
341
d02603dc 342 c = get_symbol_name (&name);
7ba29e2a
NC
343 symbolP = symbol_find_or_make (name);
344 S_SET_WEAK (symbolP);
d02603dc 345 (void) restore_line_pointer (c);
7ba29e2a
NC
346
347 SKIP_WHITESPACE ();
348
349 if (!is_end_of_line[(unsigned char) *input_line_pointer])
350 {
351 if (S_IS_DEFINED (symbolP))
352 {
353 as_bad ("Ignoring attempt to redefine symbol `%s'.",
354 S_GET_NAME (symbolP));
355 ignore_rest_of_line ();
356 return;
357 }
358
359 if (*input_line_pointer == ',')
360 {
361 ++input_line_pointer;
362 SKIP_WHITESPACE ();
363 }
364
365 expression (&exp);
366 if (exp.X_op != O_symbol)
367 {
368 as_bad ("bad .weakext directive");
369 ignore_rest_of_line ();
370 return;
371 }
372 symbol_set_value_expression (symbolP, &exp);
373 }
374
375 demand_empty_rest_of_line ();
376}
377
378/* This table describes all the machine specific pseudo-ops the assembler
379 has to support. The fields are:
380 Pseudo-op name without dot
381 Function to call to execute this pseudo-op
382 Integer arg to pass to the function. */
383/* If the pseudo-op is not found in this table, it searches in the obj-elf.c,
384 and then in the read.c table. */
385const pseudo_typeS md_pseudo_table[] =
386{
387 {"lcomm", microblaze_s_lcomm, 1},
388 {"data", microblaze_s_data, 0},
389 {"data8", cons, 1}, /* Same as byte. */
390 {"data16", cons, 2}, /* Same as hword. */
391 {"data32", cons, 4}, /* Same as word. */
392 {"ent", s_func, 0}, /* Treat ent as function entry point. */
393 {"end", microblaze_s_func, 1}, /* Treat end as function end point. */
394 {"gpword", s_rva, 4}, /* gpword label => store resolved label address in data section. */
395 {"weakext", microblaze_s_weakext, 0},
396 {"rodata", microblaze_s_rdata, 0},
397 {"sdata2", microblaze_s_rdata, 1},
398 {"sdata", microblaze_s_sdata, 0},
399 {"bss", microblaze_s_bss, 0},
400 {"sbss", microblaze_s_bss, 1},
401 {"text", microblaze_s_text, 0},
402 {"word", cons, 4},
403 {"frame", s_ignore, 0},
404 {"mask", s_ignore, 0}, /* Emitted by gcc. */
405 {NULL, NULL, 0}
406};
407
408/* This function is called once, at assembler startup time. This should
409 set up all the tables, etc that the MD part of the assembler needs. */
410
411void
412md_begin (void)
413{
52b83874 414 const struct op_code_struct * opcode;
7ba29e2a 415
629310ab 416 opcode_hash_control = str_htab_create ();
7ba29e2a
NC
417
418 /* Insert unique names into hash table. */
52b83874 419 for (opcode = microblaze_opcodes; opcode->name; opcode ++)
fe0e921f 420 str_hash_insert (opcode_hash_control, opcode->name, opcode, 0);
7ba29e2a
NC
421}
422
423/* Try to parse a reg name. */
424
425static char *
426parse_reg (char * s, unsigned * reg)
427{
428 unsigned tmpreg = 0;
429
430 /* Strip leading whitespace. */
e23c5ac0 431 while (ISSPACE (* s))
7ba29e2a
NC
432 ++ s;
433
434 if (strncasecmp (s, "rpc", 3) == 0)
435 {
436 *reg = REG_PC;
437 return s + 3;
438 }
439 else if (strncasecmp (s, "rmsr", 4) == 0)
440 {
441 *reg = REG_MSR;
442 return s + 4;
443 }
444 else if (strncasecmp (s, "rear", 4) == 0)
445 {
446 *reg = REG_EAR;
447 return s + 4;
448 }
449 else if (strncasecmp (s, "resr", 4) == 0)
450 {
451 *reg = REG_ESR;
452 return s + 4;
453 }
454 else if (strncasecmp (s, "rfsr", 4) == 0)
455 {
456 *reg = REG_FSR;
457 return s + 4;
458 }
459 else if (strncasecmp (s, "rbtr", 4) == 0)
460 {
461 *reg = REG_BTR;
462 return s + 4;
463 }
464 else if (strncasecmp (s, "redr", 4) == 0)
465 {
466 *reg = REG_EDR;
467 return s + 4;
468 }
469 /* MMU registers start. */
470 else if (strncasecmp (s, "rpid", 4) == 0)
471 {
472 *reg = REG_PID;
473 return s + 4;
474 }
475 else if (strncasecmp (s, "rzpr", 4) == 0)
476 {
477 *reg = REG_ZPR;
478 return s + 4;
479 }
480 else if (strncasecmp (s, "rtlbx", 5) == 0)
481 {
482 *reg = REG_TLBX;
483 return s + 5;
484 }
485 else if (strncasecmp (s, "rtlblo", 6) == 0)
486 {
487 *reg = REG_TLBLO;
488 return s + 6;
489 }
490 else if (strncasecmp (s, "rtlbhi", 6) == 0)
491 {
492 *reg = REG_TLBHI;
493 return s + 6;
494 }
495 else if (strncasecmp (s, "rtlbsx", 6) == 0)
496 {
497 *reg = REG_TLBSX;
498 return s + 6;
499 }
500 /* MMU registers end. */
501 else if (strncasecmp (s, "rpvr", 4) == 0)
502 {
e23c5ac0 503 if (ISDIGIT (s[4]) && ISDIGIT (s[5]))
7ba29e2a
NC
504 {
505 tmpreg = (s[4]-'0')*10 + s[5] - '0';
506 s += 6;
507 }
508
e23c5ac0 509 else if (ISDIGIT (s[4]))
7ba29e2a
NC
510 {
511 tmpreg = s[4] - '0';
512 s += 5;
513 }
514 else
515 as_bad (_("register expected, but saw '%.6s'"), s);
516 if ((int) tmpreg >= MIN_PVR_REGNUM && tmpreg <= MAX_PVR_REGNUM)
517 *reg = REG_PVR + tmpreg;
518 else
519 {
520 as_bad (_("Invalid register number at '%.6s'"), s);
521 *reg = REG_PVR;
522 }
523 return s;
524 }
525 else if (strncasecmp (s, "rsp", 3) == 0)
526 {
527 *reg = REG_SP;
528 return s + 3;
529 }
530 else if (strncasecmp (s, "rfsl", 4) == 0)
531 {
e23c5ac0 532 if (ISDIGIT (s[4]) && ISDIGIT (s[5]))
7ba29e2a
NC
533 {
534 tmpreg = (s[4] - '0') * 10 + s[5] - '0';
535 s += 6;
536 }
e23c5ac0 537 else if (ISDIGIT (s[4]))
7ba29e2a
NC
538 {
539 tmpreg = s[4] - '0';
540 s += 5;
541 }
542 else
543 as_bad (_("register expected, but saw '%.6s'"), s);
544
e23c5ac0 545 if ((int) tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM)
7ba29e2a
NC
546 *reg = tmpreg;
547 else
548 {
549 as_bad (_("Invalid register number at '%.6s'"), s);
550 *reg = 0;
551 }
552 return s;
553 }
0db4b326
ME
554 /* Stack protection registers. */
555 else if (strncasecmp (s, "rshr", 4) == 0)
556 {
557 *reg = REG_SHR;
558 return s + 4;
559 }
560 else if (strncasecmp (s, "rslr", 4) == 0)
561 {
562 *reg = REG_SLR;
563 return s + 4;
564 }
7ba29e2a
NC
565 else
566 {
e23c5ac0 567 if (TOLOWER (s[0]) == 'r')
7ba29e2a 568 {
e23c5ac0 569 if (ISDIGIT (s[1]) && ISDIGIT (s[2]))
7ba29e2a
NC
570 {
571 tmpreg = (s[1] - '0') * 10 + s[2] - '0';
572 s += 3;
573 }
e23c5ac0 574 else if (ISDIGIT (s[1]))
7ba29e2a
NC
575 {
576 tmpreg = s[1] - '0';
577 s += 2;
578 }
579 else
580 as_bad (_("register expected, but saw '%.6s'"), s);
581
582 if ((int)tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM)
583 *reg = tmpreg;
584 else
585 {
586 as_bad (_("Invalid register number at '%.6s'"), s);
587 *reg = 0;
588 }
589 return s;
590 }
591 }
592 as_bad (_("register expected, but saw '%.6s'"), s);
593 *reg = 0;
594 return s;
595}
596
597static char *
598parse_exp (char *s, expressionS *e)
599{
600 char *save;
d3ce72d0 601 char *new_pointer;
7ba29e2a
NC
602
603 /* Skip whitespace. */
e23c5ac0 604 while (ISSPACE (* s))
7ba29e2a
NC
605 ++ s;
606
607 save = input_line_pointer;
608 input_line_pointer = s;
609
610 expression (e);
611
612 if (e->X_op == O_absent)
613 as_fatal (_("missing operand"));
614
d3ce72d0 615 new_pointer = input_line_pointer;
7ba29e2a
NC
616 input_line_pointer = save;
617
d3ce72d0 618 return new_pointer;
7ba29e2a
NC
619}
620
621/* Symbol modifiers (@GOT, @PLT, @GOTOFF). */
69b06cc8 622#define IMM_NONE 0
7ba29e2a
NC
623#define IMM_GOT 1
624#define IMM_PLT 2
625#define IMM_GOTOFF 3
69b06cc8
ME
626#define IMM_TLSGD 4
627#define IMM_TLSLD 5
628#define IMM_TLSDTPMOD 6
629#define IMM_TLSDTPREL 7
630#define IMM_TLSTPREL 8
3f0a5f17
ME
631#define IMM_TXTREL 9
632#define IMM_TXTPCREL 10
633#define IMM_MAX 11
69b06cc8
ME
634
635struct imm_type {
e0471c16 636 const char *isuffix; /* Suffix String */
69b06cc8
ME
637 int itype; /* Suffix Type */
638 int otype; /* Offset Type */
639};
640
33eaf5de 641/* These are NOT in ascending order of type, GOTOFF is ahead to make
69b06cc8
ME
642 sure @GOTOFF does not get matched with @GOT */
643static struct imm_type imm_types[] = {
644 { "NONE", IMM_NONE , 0 },
645 { "GOTOFF", IMM_GOTOFF , GOTOFF_OFFSET },
646 { "GOT", IMM_GOT , GOT_OFFSET },
647 { "PLT", IMM_PLT , PLT_OFFSET },
648 { "TLSGD", IMM_TLSGD , TLSGD_OFFSET },
649 { "TLSLDM", IMM_TLSLD, TLSLD_OFFSET },
650 { "TLSDTPMOD", IMM_TLSDTPMOD, TLSDTPMOD_OFFSET },
651 { "TLSDTPREL", IMM_TLSDTPREL, TLSDTPREL_OFFSET },
3f0a5f17
ME
652 { "TLSTPREL", IMM_TLSTPREL, TLSTPREL_OFFSET },
653 { "TXTREL", IMM_TXTREL, TEXT_OFFSET },
654 { "TXTPCREL", IMM_TXTPCREL, TEXT_PC_OFFSET }
69b06cc8
ME
655};
656
657static int
658match_imm (const char *s, int *ilen)
659{
660 int i;
661 int slen;
662
663 /* Check for matching suffix */
664 for (i = 1; i < IMM_MAX; i++)
665 {
666 slen = strlen (imm_types[i].isuffix);
667
668 if (strncmp (imm_types[i].isuffix, s, slen) == 0)
669 {
670 *ilen = slen;
671 return imm_types[i].itype;
672 }
673 } /* for */
674 *ilen = 0;
675 return 0;
676}
677
678static int
679get_imm_otype (int itype)
680{
681 int i, otype;
682
683 otype = 0;
684 /* Check for matching itype */
685 for (i = 1; i < IMM_MAX; i++)
686 {
687 if (imm_types[i].itype == itype)
688 {
689 otype = imm_types[i].otype;
690 break;
691 }
692 }
693 return otype;
694}
7ba29e2a
NC
695
696static symbolS * GOT_symbol;
697
698#define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_"
699
700static char *
03e08038 701parse_imm (char * s, expressionS * e, offsetT min, offsetT max)
7ba29e2a 702{
d3ce72d0 703 char *new_pointer;
7ba29e2a 704 char *atp;
69b06cc8
ME
705 int itype, ilen;
706
707 ilen = 0;
7ba29e2a
NC
708
709 /* Find the start of "@GOT" or "@PLT" suffix (if any) */
710 for (atp = s; *atp != '@'; atp++)
711 if (is_end_of_line[(unsigned char) *atp])
712 break;
713
714 if (*atp == '@')
715 {
69b06cc8
ME
716 itype = match_imm (atp + 1, &ilen);
717 if (itype != 0)
718 {
719 *atp = 0;
720 e->X_md = itype;
721 }
7ba29e2a 722 else
69b06cc8
ME
723 {
724 atp = NULL;
725 e->X_md = 0;
726 ilen = 0;
727 }
7ba29e2a
NC
728 *atp = 0;
729 }
730 else
731 {
732 atp = NULL;
733 e->X_md = 0;
734 }
735
736 if (atp && !GOT_symbol)
737 {
738 GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
739 }
740
d3ce72d0 741 new_pointer = parse_exp (s, e);
7ba29e2a 742
d34049e8 743 if (!GOT_symbol && startswith (s, GOT_SYMBOL_NAME))
69b06cc8
ME
744 {
745 GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
746 }
747
7ba29e2a
NC
748 if (e->X_op == O_absent)
749 ; /* An error message has already been emitted. */
750 else if ((e->X_op != O_constant && e->X_op != O_symbol) )
751 as_fatal (_("operand must be a constant or a label"));
f66adc4e 752 else if (e->X_op == O_constant)
7ba29e2a 753 {
ac0d427f 754 /* Special case: sign extend negative 32-bit values to offsetT size. */
f66adc4e 755 if ((e->X_add_number >> 31) == 1)
ac0d427f 756 e->X_add_number |= -((addressT) (1U << 31));
f66adc4e 757
2677a570 758 if ((int)e->X_add_number < min || (int)e->X_add_number > max)
f66adc4e
NC
759 {
760 as_fatal (_("operand must be absolute in range %lx..%lx, not %lx"),
761 (long) min, (long) max, (long) e->X_add_number);
762 }
7ba29e2a
NC
763 }
764
765 if (atp)
766 {
767 *atp = '@'; /* restore back (needed?) */
d3ce72d0 768 if (new_pointer >= atp)
69b06cc8 769 new_pointer += ilen + 1; /* sizeof (imm_suffix) + 1 for '@' */
7ba29e2a 770 }
d3ce72d0 771 return new_pointer;
7ba29e2a
NC
772}
773
774static char *
775check_got (int * got_type, int * got_len)
776{
d3ce72d0 777 char *new_pointer;
7ba29e2a
NC
778 char *atp;
779 char *past_got;
780 int first, second;
781 char *tmpbuf;
782
783 /* Find the start of "@GOT" or "@PLT" suffix (if any). */
784 for (atp = input_line_pointer; *atp != '@'; atp++)
785 if (is_end_of_line[(unsigned char) *atp])
786 return NULL;
787
d34049e8 788 if (startswith (atp + 1, "GOTOFF"))
7ba29e2a
NC
789 {
790 *got_len = 6;
791 *got_type = IMM_GOTOFF;
792 }
d34049e8 793 else if (startswith (atp + 1, "GOT"))
7ba29e2a
NC
794 {
795 *got_len = 3;
796 *got_type = IMM_GOT;
797 }
d34049e8 798 else if (startswith (atp + 1, "PLT"))
7ba29e2a
NC
799 {
800 *got_len = 3;
801 *got_type = IMM_PLT;
802 }
803 else
804 return NULL;
805
806 if (!GOT_symbol)
807 GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
808
809 first = atp - input_line_pointer;
810
811 past_got = atp + *got_len + 1;
d3ce72d0 812 for (new_pointer = past_got; !is_end_of_line[(unsigned char) *new_pointer++];)
7ba29e2a 813 ;
d3ce72d0 814 second = new_pointer - past_got;
325801bd
TS
815 /* One extra byte for ' ' and one for NUL. */
816 tmpbuf = XNEWVEC (char, first + second + 2);
7ba29e2a
NC
817 memcpy (tmpbuf, input_line_pointer, first);
818 tmpbuf[first] = ' '; /* @GOTOFF is replaced with a single space. */
819 memcpy (tmpbuf + first + 1, past_got, second);
820 tmpbuf[first + second + 1] = '\0';
821
822 return tmpbuf;
823}
824
62ebcb5c 825extern bfd_reloc_code_real_type
7ba29e2a
NC
826parse_cons_expression_microblaze (expressionS *exp, int size)
827{
828 if (size == 4)
829 {
830 /* Handle @GOTOFF et.al. */
831 char *save, *gotfree_copy;
832 int got_len, got_type;
833
834 save = input_line_pointer;
835 gotfree_copy = check_got (& got_type, & got_len);
836 if (gotfree_copy)
837 input_line_pointer = gotfree_copy;
838
839 expression (exp);
840
841 if (gotfree_copy)
842 {
843 exp->X_md = got_type;
844 input_line_pointer = save + (input_line_pointer - gotfree_copy)
845 + got_len;
846 free (gotfree_copy);
847 }
848 }
849 else
850 expression (exp);
62ebcb5c 851 return BFD_RELOC_NONE;
7ba29e2a
NC
852}
853
854/* This is the guts of the machine-dependent assembler. STR points to a
855 machine dependent instruction. This function is supposed to emit
856 the frags/bytes it assembles to. */
857
e742e119
TS
858static const char * str_microblaze_ro_anchor = "RO";
859static const char * str_microblaze_rw_anchor = "RW";
7ba29e2a 860
5b7c81bd 861static bool
7ba29e2a
NC
862check_spl_reg (unsigned * reg)
863{
864 if ((*reg == REG_MSR) || (*reg == REG_PC)
865 || (*reg == REG_EAR) || (*reg == REG_ESR)
866 || (*reg == REG_FSR) || (*reg == REG_BTR) || (*reg == REG_EDR)
867 || (*reg == REG_PID) || (*reg == REG_ZPR)
868 || (*reg == REG_TLBX) || (*reg == REG_TLBLO)
869 || (*reg == REG_TLBHI) || (*reg == REG_TLBSX)
0db4b326 870 || (*reg == REG_SHR) || (*reg == REG_SLR)
7ba29e2a 871 || (*reg >= REG_PVR+MIN_PVR_REGNUM && *reg <= REG_PVR+MAX_PVR_REGNUM))
5b7c81bd 872 return true;
7ba29e2a 873
5b7c81bd 874 return false;
7ba29e2a
NC
875}
876
877/* Here we decide which fixups can be adjusted to make them relative to
878 the beginning of the section instead of the symbol. Basically we need
879 to make sure that the dynamic relocations are done correctly, so in
880 some cases we force the original symbol to be used. */
881
882int
883tc_microblaze_fix_adjustable (struct fix *fixP)
884{
885 if (GOT_symbol && fixP->fx_subsy == GOT_symbol)
886 return 0;
887
888 if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOTOFF
889 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_GOTOFF
890 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOT
69b06cc8
ME
891 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PLT
892 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGD
893 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSLD
894 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPMOD
895 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPREL
896 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSDTPREL
897 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL
898 || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSTPREL)
7ba29e2a
NC
899 return 0;
900
901 return 1;
902}
903
904void
905md_assemble (char * str)
906{
907 char * op_start;
908 char * op_end;
909 struct op_code_struct * opcode, *opcode1;
910 char * output = NULL;
911 int nlen = 0;
912 int i;
913 unsigned long inst, inst1;
914 unsigned reg1;
915 unsigned reg2;
916 unsigned reg3;
917 unsigned isize;
bb0d05ff 918 unsigned int immed = 0, immed2 = 0, temp;
7ba29e2a
NC
919 expressionS exp;
920 char name[20];
921
922 /* Drop leading whitespace. */
e23c5ac0 923 while (ISSPACE (* str))
7ba29e2a
NC
924 str ++;
925
926 /* Find the op code end. */
927 for (op_start = op_end = str;
4ad7ac30 928 *op_end && !is_end_of_line[(unsigned char) *op_end] && *op_end != ' ';
7ba29e2a
NC
929 op_end++)
930 {
931 name[nlen] = op_start[nlen];
932 nlen++;
4ad7ac30
AM
933 if (nlen == sizeof (name) - 1)
934 break;
7ba29e2a
NC
935 }
936
937 name [nlen] = 0;
938
939 if (nlen == 0)
940 {
941 as_bad (_("can't find opcode "));
942 return;
943 }
944
629310ab 945 opcode = (struct op_code_struct *) str_hash_find (opcode_hash_control, name);
7ba29e2a
NC
946 if (opcode == NULL)
947 {
948 as_bad (_("unknown opcode \"%s\""), name);
949 return;
950 }
951
952 inst = opcode->bit_sequence;
953 isize = 4;
954
955 switch (opcode->inst_type)
956 {
957 case INST_TYPE_RD_R1_R2:
958 if (strcmp (op_end, ""))
959 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
960 else
961 {
962 as_fatal (_("Error in statement syntax"));
963 reg1 = 0;
964 }
965 if (strcmp (op_end, ""))
966 op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
967 else
968 {
969 as_fatal (_("Error in statement syntax"));
970 reg2 = 0;
971 }
972 if (strcmp (op_end, ""))
973 op_end = parse_reg (op_end + 1, &reg3); /* Get r2. */
974 else
975 {
976 as_fatal (_("Error in statement syntax"));
977 reg3 = 0;
978 }
979
980 /* Check for spl registers. */
981 if (check_spl_reg (& reg1))
982 as_fatal (_("Cannot use special register with this instruction"));
983 if (check_spl_reg (& reg2))
984 as_fatal (_("Cannot use special register with this instruction"));
985 if (check_spl_reg (& reg3))
986 as_fatal (_("Cannot use special register with this instruction"));
987
988 if (streq (name, "sub"))
989 {
990 /* sub rd, r1, r2 becomes rsub rd, r2, r1. */
991 inst |= (reg1 << RD_LOW) & RD_MASK;
992 inst |= (reg3 << RA_LOW) & RA_MASK;
993 inst |= (reg2 << RB_LOW) & RB_MASK;
994 }
995 else
996 {
997 inst |= (reg1 << RD_LOW) & RD_MASK;
998 inst |= (reg2 << RA_LOW) & RA_MASK;
999 inst |= (reg3 << RB_LOW) & RB_MASK;
1000 }
1001 output = frag_more (isize);
1002 break;
1003
1004 case INST_TYPE_RD_R1_IMM:
1005 if (strcmp (op_end, ""))
1006 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1007 else
1008 {
1009 as_fatal (_("Error in statement syntax"));
1010 reg1 = 0;
1011 }
1012 if (strcmp (op_end, ""))
1013 op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
1014 else
1015 {
1016 as_fatal (_("Error in statement syntax"));
1017 reg2 = 0;
1018 }
1019 if (strcmp (op_end, ""))
1020 op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1021 else
1022 as_fatal (_("Error in statement syntax"));
1023
1024 /* Check for spl registers. */
1025 if (check_spl_reg (& reg1))
1026 as_fatal (_("Cannot use special register with this instruction"));
1027 if (check_spl_reg (& reg2))
1028 as_fatal (_("Cannot use special register with this instruction"));
1029
3f0a5f17 1030 if (exp.X_op != O_constant || exp.X_md == IMM_TXTPCREL)
7ba29e2a 1031 {
e742e119 1032 const char *opc;
7ba29e2a
NC
1033 relax_substateT subtype;
1034
1035 if (streq (name, "lmi"))
1036 as_fatal (_("lmi pseudo instruction should not use a label in imm field"));
1037 else if (streq (name, "smi"))
1038 as_fatal (_("smi pseudo instruction should not use a label in imm field"));
1039
1040 if (reg2 == REG_ROSDP)
1041 opc = str_microblaze_ro_anchor;
1042 else if (reg2 == REG_RWSDP)
1043 opc = str_microblaze_rw_anchor;
1044 else
1045 opc = NULL;
69b06cc8
ME
1046 if (exp.X_md != 0)
1047 subtype = get_imm_otype(exp.X_md);
7ba29e2a
NC
1048 else
1049 subtype = opcode->inst_offset_type;
1050
1051 output = frag_var (rs_machine_dependent,
1052 isize * 2, /* maxm of 2 words. */
1053 isize, /* minm of 1 word. */
1054 subtype, /* PC-relative or not. */
1055 exp.X_add_symbol,
1056 exp.X_add_number,
e742e119 1057 (char *) opc);
c7d6f518 1058 immed = 0;
7ba29e2a
NC
1059 }
1060 else
1061 {
1062 output = frag_more (isize);
c7d6f518 1063 immed = exp.X_add_number;
7ba29e2a
NC
1064 }
1065
1066 if (streq (name, "lmi") || streq (name, "smi"))
1067 {
1068 /* Load/store 32-d consecutive registers. Used on exit/entry
1069 to subroutines to save and restore registers to stack.
1070 Generate 32-d insts. */
1071 int count;
1072
1073 count = 32 - reg1;
1074 if (streq (name, "lmi"))
fe0e921f
AM
1075 opcode
1076 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1077 "lwi");
7ba29e2a 1078 else
fe0e921f
AM
1079 opcode
1080 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1081 "swi");
7ba29e2a
NC
1082 if (opcode == NULL)
1083 {
1084 as_bad (_("unknown opcode \"%s\""), "lwi");
1085 return;
1086 }
1087 inst = opcode->bit_sequence;
1088 inst |= (reg1 << RD_LOW) & RD_MASK;
1089 inst |= (reg2 << RA_LOW) & RA_MASK;
c7d6f518 1090 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1091
1092 for (i = 0; i < count - 1; i++)
1093 {
1094 output[0] = INST_BYTE0 (inst);
1095 output[1] = INST_BYTE1 (inst);
1096 output[2] = INST_BYTE2 (inst);
1097 output[3] = INST_BYTE3 (inst);
1098 output = frag_more (isize);
c7d6f518 1099 immed = immed + 4;
7ba29e2a
NC
1100 reg1++;
1101 inst = opcode->bit_sequence;
1102 inst |= (reg1 << RD_LOW) & RD_MASK;
1103 inst |= (reg2 << RA_LOW) & RA_MASK;
c7d6f518 1104 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1105 }
1106 }
1107 else
1108 {
c7d6f518 1109 temp = immed & 0xFFFF8000;
7ba29e2a
NC
1110 if ((temp != 0) && (temp != 0xFFFF8000))
1111 {
1112 /* Needs an immediate inst. */
fe0e921f
AM
1113 opcode1
1114 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1115 "imm");
7ba29e2a
NC
1116 if (opcode1 == NULL)
1117 {
1118 as_bad (_("unknown opcode \"%s\""), "imm");
1119 return;
1120 }
1121
1122 inst1 = opcode1->bit_sequence;
c7d6f518 1123 inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
7ba29e2a
NC
1124 output[0] = INST_BYTE0 (inst1);
1125 output[1] = INST_BYTE1 (inst1);
1126 output[2] = INST_BYTE2 (inst1);
1127 output[3] = INST_BYTE3 (inst1);
1128 output = frag_more (isize);
1129 }
1130 inst |= (reg1 << RD_LOW) & RD_MASK;
1131 inst |= (reg2 << RA_LOW) & RA_MASK;
c7d6f518 1132 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1133 }
1134 break;
1135
1136 case INST_TYPE_RD_R1_IMM5:
1137 if (strcmp (op_end, ""))
1138 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1139 else
1140 {
1141 as_fatal (_("Error in statement syntax"));
1142 reg1 = 0;
1143 }
1144 if (strcmp (op_end, ""))
1145 op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
1146 else
1147 {
1148 as_fatal (_("Error in statement syntax"));
1149 reg2 = 0;
1150 }
1151 if (strcmp (op_end, ""))
1152 op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1153 else
1154 as_fatal (_("Error in statement syntax"));
1155
1156 /* Check for spl registers. */
1157 if (check_spl_reg (&reg1))
1158 as_fatal (_("Cannot use special register with this instruction"));
1159 if (check_spl_reg (&reg2))
1160 as_fatal (_("Cannot use special register with this instruction"));
1161
1162 if (exp.X_op != O_constant)
1163 as_warn (_("Symbol used as immediate for shift instruction"));
1164 else
1165 {
1166 output = frag_more (isize);
c7d6f518 1167 immed = exp.X_add_number;
7ba29e2a
NC
1168 }
1169
c7d6f518 1170 if (immed != (immed % 32))
7ba29e2a
NC
1171 {
1172 as_warn (_("Shift value > 32. using <value %% 32>"));
c7d6f518 1173 immed = immed % 32;
7ba29e2a
NC
1174 }
1175 inst |= (reg1 << RD_LOW) & RD_MASK;
1176 inst |= (reg2 << RA_LOW) & RA_MASK;
c7d6f518 1177 inst |= (immed << IMM_LOW) & IMM5_MASK;
7ba29e2a
NC
1178 break;
1179
bb0d05ff
NF
1180 case INST_TYPE_RD_R1_IMMW_IMMS:
1181 if (strcmp (op_end, ""))
1182 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1183 else
1184 {
1185 as_fatal (_("Error in statement syntax"));
1186 reg1 = 0;
1187 }
1188
1189 if (strcmp (op_end, ""))
1190 op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
1191 else
1192 {
1193 as_fatal (_("Error in statement syntax"));
1194 reg2 = 0;
1195 }
1196
1197 /* Check for spl registers. */
1198 if (check_spl_reg (&reg1))
1199 as_fatal (_("Cannot use special register with this instruction"));
1200 if (check_spl_reg (&reg2))
1201 as_fatal (_("Cannot use special register with this instruction"));
1202
1203 /* Width immediate value. */
1204 if (strcmp (op_end, ""))
1205 op_end = parse_imm (op_end + 1, &exp, MIN_IMM_WIDTH, MAX_IMM_WIDTH);
1206 else
1207 as_fatal (_("Error in statement syntax"));
1208
1209 if (exp.X_op != O_constant)
1210 {
1211 as_warn (_(
1212 "Symbol used as immediate width value for bit field instruction"));
1213 immed = 1;
1214 }
1215 else
1216 immed = exp.X_add_number;
1217
1218 if (opcode->instr == bsefi && immed > 31)
1219 as_fatal (_("Width value must be less than 32"));
1220
1221 /* Shift immediate value. */
1222 if (strcmp (op_end, ""))
1223 op_end = parse_imm (op_end + 1, &exp, MIN_IMM, MAX_IMM);
1224 else
1225 as_fatal (_("Error in statement syntax"));
1226
1227 if (exp.X_op != O_constant)
1228 {
1229 as_warn (_(
1230 "Symbol used as immediate shift value for bit field instruction"));
1231 immed2 = 0;
1232 }
1233 else
1234 {
1235 output = frag_more (isize);
1236 immed2 = exp.X_add_number;
1237 }
1238
1239 if (immed2 != (immed2 % 32))
1240 {
1241 as_warn (_("Shift value greater than 32. using <value %% 32>"));
1242 immed2 = immed2 % 32;
1243 }
1244
1245 /* Check combined value. */
1246 if (immed + immed2 > 32)
1247 as_fatal (_("Width value + shift value must not be greater than 32"));
1248
1249 inst |= (reg1 << RD_LOW) & RD_MASK;
1250 inst |= (reg2 << RA_LOW) & RA_MASK;
1251
1252 if (opcode->instr == bsefi)
1253 inst |= (immed & IMM5_MASK) << IMM_WIDTH_LOW; /* bsefi */
1254 else
1255 inst |= ((immed + immed2 - 1) & IMM5_MASK)
1256 << IMM_WIDTH_LOW; /* bsifi */
1257
1258 inst |= (immed2 << IMM_LOW) & IMM5_MASK;
1259 break;
1260
7ba29e2a
NC
1261 case INST_TYPE_R1_R2:
1262 if (strcmp (op_end, ""))
1263 op_end = parse_reg (op_end + 1, &reg1); /* Get r1. */
1264 else
1265 {
1266 as_fatal (_("Error in statement syntax"));
1267 reg1 = 0;
1268 }
1269 if (strcmp (op_end, ""))
1270 op_end = parse_reg (op_end + 1, &reg2); /* Get r2. */
1271 else
1272 {
1273 as_fatal (_("Error in statement syntax"));
1274 reg2 = 0;
1275 }
1276
1277 /* Check for spl registers. */
1278 if (check_spl_reg (& reg1))
1279 as_fatal (_("Cannot use special register with this instruction"));
1280 if (check_spl_reg (& reg2))
1281 as_fatal (_("Cannot use special register with this instruction"));
1282
1283 inst |= (reg1 << RA_LOW) & RA_MASK;
1284 inst |= (reg2 << RB_LOW) & RB_MASK;
1285 output = frag_more (isize);
1286 break;
1287
1288 case INST_TYPE_RD_R1:
1289 if (strcmp (op_end, ""))
1290 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1291 else
1292 {
1293 as_fatal (_("Error in statement syntax"));
1294 reg1 = 0;
1295 }
1296 if (strcmp (op_end, ""))
1297 op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
1298 else
1299 {
1300 as_fatal (_("Error in statement syntax"));
1301 reg2 =0;
1302 }
1303
1304 /* Check for spl registers. */
1305 if (check_spl_reg (&reg1))
1306 as_fatal (_("Cannot use special register with this instruction"));
1307 if (check_spl_reg (&reg2))
1308 as_fatal (_("Cannot use special register with this instruction"));
1309
1310 inst |= (reg1 << RD_LOW) & RD_MASK;
1311 inst |= (reg2 << RA_LOW) & RA_MASK;
1312 output = frag_more (isize);
1313 break;
1314
1315 case INST_TYPE_RD_RFSL:
1316 if (strcmp (op_end, ""))
1317 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1318 else
1319 {
1320 as_fatal (_("Error in statement syntax"));
1321 reg1 = 0;
1322 }
1323 if (strcmp (op_end, ""))
c7d6f518 1324 op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */
7ba29e2a
NC
1325 else
1326 {
1327 as_fatal (_("Error in statement syntax"));
c7d6f518 1328 immed = 0;
7ba29e2a
NC
1329 }
1330
1331 /* Check for spl registers. */
1332 if (check_spl_reg (&reg1))
1333 as_fatal (_("Cannot use special register with this instruction"));
1334
1335 inst |= (reg1 << RD_LOW) & RD_MASK;
c7d6f518 1336 inst |= (immed << IMM_LOW) & RFSL_MASK;
7ba29e2a
NC
1337 output = frag_more (isize);
1338 break;
1339
1340 case INST_TYPE_RD_IMM15:
1341 if (strcmp (op_end, ""))
1342 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1343 else
1344 {
1345 as_fatal (_("Error in statement syntax"));
1346 reg1 = 0;
1347 }
1348
1349 if (strcmp (op_end, ""))
1350 op_end = parse_imm (op_end + 1, & exp, MIN_IMM15, MAX_IMM15);
1351 else
1352 as_fatal (_("Error in statement syntax"));
1353
1354 /* Check for spl registers. */
1355 if (check_spl_reg (&reg1))
1356 as_fatal (_("Cannot use special register with this instruction"));
1357
1358 if (exp.X_op != O_constant)
1359 as_fatal (_("Symbol used as immediate value for msrset/msrclr instructions"));
1360 else
1361 {
1362 output = frag_more (isize);
c7d6f518 1363 immed = exp.X_add_number;
7ba29e2a
NC
1364 }
1365 inst |= (reg1 << RD_LOW) & RD_MASK;
c7d6f518 1366 inst |= (immed << IMM_LOW) & IMM15_MASK;
7ba29e2a
NC
1367 break;
1368
1369 case INST_TYPE_R1_RFSL:
1370 if (strcmp (op_end, ""))
1371 op_end = parse_reg (op_end + 1, &reg1); /* Get r1. */
1372 else
1373 {
1374 as_fatal (_("Error in statement syntax"));
1375 reg1 = 0;
1376 }
1377 if (strcmp (op_end, ""))
c7d6f518 1378 op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */
7ba29e2a
NC
1379 else
1380 {
1381 as_fatal (_("Error in statement syntax"));
c7d6f518 1382 immed = 0;
7ba29e2a
NC
1383 }
1384
1385 /* Check for spl registers. */
1386 if (check_spl_reg (&reg1))
1387 as_fatal (_("Cannot use special register with this instruction"));
1388
1389 inst |= (reg1 << RA_LOW) & RA_MASK;
c7d6f518 1390 inst |= (immed << IMM_LOW) & RFSL_MASK;
7ba29e2a
NC
1391 output = frag_more (isize);
1392 break;
1393
1394 case INST_TYPE_RFSL:
1395 if (strcmp (op_end, ""))
c7d6f518 1396 op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */
7ba29e2a
NC
1397 else
1398 {
1399 as_fatal (_("Error in statement syntax"));
c7d6f518 1400 immed = 0;
7ba29e2a 1401 }
c7d6f518 1402 inst |= (immed << IMM_LOW) & RFSL_MASK;
7ba29e2a
NC
1403 output = frag_more (isize);
1404 break;
1405
1406 case INST_TYPE_R1:
1407 if (strcmp (op_end, ""))
1408 op_end = parse_reg (op_end + 1, &reg1); /* Get r1. */
1409 else
1410 {
1411 as_fatal (_("Error in statement syntax"));
1412 reg1 = 0;
1413 }
1414
1415 /* Check for spl registers. */
1416 if (check_spl_reg (&reg1))
1417 as_fatal (_("Cannot use special register with this instruction"));
1418
1419 inst |= (reg1 << RA_LOW) & RA_MASK;
1420 output = frag_more (isize);
1421 break;
1422
1423 /* For tuqula insn...:) */
1424 case INST_TYPE_RD:
1425 if (strcmp (op_end, ""))
1426 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1427 else
1428 {
1429 as_fatal (_("Error in statement syntax"));
1430 reg1 = 0;
1431 }
1432
1433 /* Check for spl registers. */
1434 if (check_spl_reg (&reg1))
1435 as_fatal (_("Cannot use special register with this instruction"));
1436
1437 inst |= (reg1 << RD_LOW) & RD_MASK;
1438 output = frag_more (isize);
1439 break;
1440
1441 case INST_TYPE_RD_SPECIAL:
1442 if (strcmp (op_end, ""))
1443 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1444 else
1445 {
1446 as_fatal (_("Error in statement syntax"));
1447 reg1 = 0;
1448 }
1449 if (strcmp (op_end, ""))
1450 op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
1451 else
1452 {
1453 as_fatal (_("Error in statement syntax"));
1454 reg2 = 0;
1455 }
1456
1457 if (reg2 == REG_MSR)
c7d6f518 1458 immed = opcode->immval_mask | REG_MSR_MASK;
7ba29e2a 1459 else if (reg2 == REG_PC)
c7d6f518 1460 immed = opcode->immval_mask | REG_PC_MASK;
7ba29e2a 1461 else if (reg2 == REG_EAR)
c7d6f518 1462 immed = opcode->immval_mask | REG_EAR_MASK;
7ba29e2a 1463 else if (reg2 == REG_ESR)
c7d6f518 1464 immed = opcode->immval_mask | REG_ESR_MASK;
7ba29e2a 1465 else if (reg2 == REG_FSR)
c7d6f518 1466 immed = opcode->immval_mask | REG_FSR_MASK;
7ba29e2a 1467 else if (reg2 == REG_BTR)
c7d6f518 1468 immed = opcode->immval_mask | REG_BTR_MASK;
7ba29e2a 1469 else if (reg2 == REG_EDR)
c7d6f518 1470 immed = opcode->immval_mask | REG_EDR_MASK;
7ba29e2a 1471 else if (reg2 == REG_PID)
c7d6f518 1472 immed = opcode->immval_mask | REG_PID_MASK;
7ba29e2a 1473 else if (reg2 == REG_ZPR)
c7d6f518 1474 immed = opcode->immval_mask | REG_ZPR_MASK;
7ba29e2a 1475 else if (reg2 == REG_TLBX)
c7d6f518 1476 immed = opcode->immval_mask | REG_TLBX_MASK;
7ba29e2a 1477 else if (reg2 == REG_TLBLO)
c7d6f518 1478 immed = opcode->immval_mask | REG_TLBLO_MASK;
7ba29e2a 1479 else if (reg2 == REG_TLBHI)
c7d6f518 1480 immed = opcode->immval_mask | REG_TLBHI_MASK;
0db4b326
ME
1481 else if (reg2 == REG_SHR)
1482 immed = opcode->immval_mask | REG_SHR_MASK;
1483 else if (reg2 == REG_SLR)
1484 immed = opcode->immval_mask | REG_SLR_MASK;
7ba29e2a 1485 else if (reg2 >= (REG_PVR+MIN_PVR_REGNUM) && reg2 <= (REG_PVR+MAX_PVR_REGNUM))
c7d6f518 1486 immed = opcode->immval_mask | REG_PVR_MASK | reg2;
7ba29e2a
NC
1487 else
1488 as_fatal (_("invalid value for special purpose register"));
1489 inst |= (reg1 << RD_LOW) & RD_MASK;
c7d6f518 1490 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1491 output = frag_more (isize);
1492 break;
1493
1494 case INST_TYPE_SPECIAL_R1:
1495 if (strcmp (op_end, ""))
1496 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1497 else
1498 {
1499 as_fatal (_("Error in statement syntax"));
1500 reg1 = 0;
1501 }
1502 if (strcmp (op_end, ""))
1503 op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
1504 else
1505 {
1506 as_fatal (_("Error in statement syntax"));
1507 reg2 = 0;
1508 }
1509
1510 if (reg1 == REG_MSR)
c7d6f518 1511 immed = opcode->immval_mask | REG_MSR_MASK;
7ba29e2a 1512 else if (reg1 == REG_PC)
c7d6f518 1513 immed = opcode->immval_mask | REG_PC_MASK;
7ba29e2a 1514 else if (reg1 == REG_EAR)
c7d6f518 1515 immed = opcode->immval_mask | REG_EAR_MASK;
7ba29e2a 1516 else if (reg1 == REG_ESR)
c7d6f518 1517 immed = opcode->immval_mask | REG_ESR_MASK;
7ba29e2a 1518 else if (reg1 == REG_FSR)
c7d6f518 1519 immed = opcode->immval_mask | REG_FSR_MASK;
7ba29e2a 1520 else if (reg1 == REG_BTR)
c7d6f518 1521 immed = opcode->immval_mask | REG_BTR_MASK;
7ba29e2a 1522 else if (reg1 == REG_EDR)
c7d6f518 1523 immed = opcode->immval_mask | REG_EDR_MASK;
7ba29e2a 1524 else if (reg1 == REG_PID)
c7d6f518 1525 immed = opcode->immval_mask | REG_PID_MASK;
7ba29e2a 1526 else if (reg1 == REG_ZPR)
c7d6f518 1527 immed = opcode->immval_mask | REG_ZPR_MASK;
7ba29e2a 1528 else if (reg1 == REG_TLBX)
c7d6f518 1529 immed = opcode->immval_mask | REG_TLBX_MASK;
7ba29e2a 1530 else if (reg1 == REG_TLBLO)
c7d6f518 1531 immed = opcode->immval_mask | REG_TLBLO_MASK;
7ba29e2a 1532 else if (reg1 == REG_TLBHI)
c7d6f518 1533 immed = opcode->immval_mask | REG_TLBHI_MASK;
7ba29e2a 1534 else if (reg1 == REG_TLBSX)
c7d6f518 1535 immed = opcode->immval_mask | REG_TLBSX_MASK;
0db4b326
ME
1536 else if (reg1 == REG_SHR)
1537 immed = opcode->immval_mask | REG_SHR_MASK;
1538 else if (reg1 == REG_SLR)
1539 immed = opcode->immval_mask | REG_SLR_MASK;
7ba29e2a
NC
1540 else
1541 as_fatal (_("invalid value for special purpose register"));
1542 inst |= (reg2 << RA_LOW) & RA_MASK;
c7d6f518 1543 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1544 output = frag_more (isize);
1545 break;
1546
94dda8b7 1547 case INST_TYPE_R1_R2_SPECIAL:
7ba29e2a 1548 if (strcmp (op_end, ""))
94dda8b7 1549 op_end = parse_reg (op_end + 1, &reg1); /* Get r1. */
7ba29e2a
NC
1550 else
1551 {
1552 as_fatal (_("Error in statement syntax"));
1553 reg1 = 0;
1554 }
1555 if (strcmp (op_end, ""))
94dda8b7 1556 op_end = parse_reg (op_end + 1, &reg2); /* Get r2. */
7ba29e2a
NC
1557 else
1558 {
1559 as_fatal (_("Error in statement syntax"));
1560 reg2 =0;
1561 }
1562
1563 /* Check for spl registers. */
1564 if (check_spl_reg (&reg1))
1565 as_fatal (_("Cannot use special register with this instruction"));
1566 if (check_spl_reg (&reg2))
1567 as_fatal (_("Cannot use special register with this instruction"));
1568
1569 /* insn wic ra, rb => wic ra, ra, rb. */
7ba29e2a
NC
1570 inst |= (reg1 << RA_LOW) & RA_MASK;
1571 inst |= (reg2 << RB_LOW) & RB_MASK;
1572
1573 output = frag_more (isize);
1574 break;
1575
1576 case INST_TYPE_RD_R2:
1577 if (strcmp (op_end, ""))
1578 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1579 else
1580 {
1581 as_fatal (_("Error in statement syntax"));
1582 reg1 = 0;
1583 }
1584 if (strcmp (op_end, ""))
1585 op_end = parse_reg (op_end + 1, &reg2); /* Get r2. */
1586 else
1587 {
1588 as_fatal (_("Error in statement syntax"));
1589 reg2 = 0;
1590 }
1591
1592 /* Check for spl registers. */
1593 if (check_spl_reg (&reg1))
1594 as_fatal (_("Cannot use special register with this instruction"));
1595 if (check_spl_reg (&reg2))
1596 as_fatal (_("Cannot use special register with this instruction"));
1597
1598 inst |= (reg1 << RD_LOW) & RD_MASK;
1599 inst |= (reg2 << RB_LOW) & RB_MASK;
1600 output = frag_more (isize);
1601 break;
1602
1603 case INST_TYPE_R1_IMM:
1604 if (strcmp (op_end, ""))
1605 op_end = parse_reg (op_end + 1, &reg1); /* Get r1. */
1606 else
1607 {
1608 as_fatal (_("Error in statement syntax"));
1609 reg1 = 0;
1610 }
1611 if (strcmp (op_end, ""))
1612 op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1613 else
1614 as_fatal (_("Error in statement syntax"));
1615
1616 /* Check for spl registers. */
1617 if (check_spl_reg (&reg1))
1618 as_fatal (_("Cannot use special register with this instruction"));
1619
1620 if (exp.X_op != O_constant)
1621 {
1622 char *opc = NULL;
1623 relax_substateT subtype;
1624
69b06cc8
ME
1625 if (exp.X_md != 0)
1626 subtype = get_imm_otype(exp.X_md);
7ba29e2a
NC
1627 else
1628 subtype = opcode->inst_offset_type;
69b06cc8 1629
7ba29e2a
NC
1630 output = frag_var (rs_machine_dependent,
1631 isize * 2, /* maxm of 2 words. */
1632 isize, /* minm of 1 word. */
1633 subtype, /* PC-relative or not. */
1634 exp.X_add_symbol,
1635 exp.X_add_number,
1636 opc);
c7d6f518 1637 immed = 0;
7ba29e2a
NC
1638 }
1639 else
1640 {
1641 output = frag_more (isize);
c7d6f518 1642 immed = exp.X_add_number;
7ba29e2a
NC
1643 }
1644
c7d6f518 1645 temp = immed & 0xFFFF8000;
7ba29e2a
NC
1646 if ((temp != 0) && (temp != 0xFFFF8000))
1647 {
1648 /* Needs an immediate inst. */
fe0e921f
AM
1649 opcode1
1650 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1651 "imm");
7ba29e2a
NC
1652 if (opcode1 == NULL)
1653 {
1654 as_bad (_("unknown opcode \"%s\""), "imm");
1655 return;
1656 }
1657
1658 inst1 = opcode1->bit_sequence;
c7d6f518 1659 inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
7ba29e2a
NC
1660 output[0] = INST_BYTE0 (inst1);
1661 output[1] = INST_BYTE1 (inst1);
1662 output[2] = INST_BYTE2 (inst1);
1663 output[3] = INST_BYTE3 (inst1);
1664 output = frag_more (isize);
1665 }
1666
1667 inst |= (reg1 << RA_LOW) & RA_MASK;
c7d6f518 1668 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1669 break;
1670
1671 case INST_TYPE_RD_IMM:
1672 if (strcmp (op_end, ""))
1673 op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
1674 else
1675 {
1676 as_fatal (_("Error in statement syntax"));
1677 reg1 = 0;
1678 }
1679 if (strcmp (op_end, ""))
1680 op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1681 else
1682 as_fatal (_("Error in statement syntax"));
1683
1684 /* Check for spl registers. */
1685 if (check_spl_reg (&reg1))
1686 as_fatal (_("Cannot use special register with this instruction"));
1687
1688 if (exp.X_op != O_constant)
1689 {
1690 char *opc = NULL;
1691 relax_substateT subtype;
1692
69b06cc8
ME
1693 if (exp.X_md != 0)
1694 subtype = get_imm_otype(exp.X_md);
1695 else
7ba29e2a 1696 subtype = opcode->inst_offset_type;
69b06cc8 1697
7ba29e2a
NC
1698 output = frag_var (rs_machine_dependent,
1699 isize * 2, /* maxm of 2 words. */
1700 isize, /* minm of 1 word. */
1701 subtype, /* PC-relative or not. */
1702 exp.X_add_symbol,
1703 exp.X_add_number,
1704 opc);
c7d6f518 1705 immed = 0;
7ba29e2a
NC
1706 }
1707 else
1708 {
1709 output = frag_more (isize);
c7d6f518 1710 immed = exp.X_add_number;
7ba29e2a
NC
1711 }
1712
c7d6f518 1713 temp = immed & 0xFFFF8000;
7ba29e2a
NC
1714 if ((temp != 0) && (temp != 0xFFFF8000))
1715 {
1716 /* Needs an immediate inst. */
fe0e921f
AM
1717 opcode1
1718 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1719 "imm");
7ba29e2a
NC
1720 if (opcode1 == NULL)
1721 {
1722 as_bad (_("unknown opcode \"%s\""), "imm");
1723 return;
1724 }
1725
1726 inst1 = opcode1->bit_sequence;
c7d6f518 1727 inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
7ba29e2a
NC
1728 output[0] = INST_BYTE0 (inst1);
1729 output[1] = INST_BYTE1 (inst1);
1730 output[2] = INST_BYTE2 (inst1);
1731 output[3] = INST_BYTE3 (inst1);
1732 output = frag_more (isize);
1733 }
1734
1735 inst |= (reg1 << RD_LOW) & RD_MASK;
c7d6f518 1736 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1737 break;
1738
1739 case INST_TYPE_R2:
1740 if (strcmp (op_end, ""))
1741 op_end = parse_reg (op_end + 1, &reg2); /* Get r2. */
1742 else
1743 {
1744 as_fatal (_("Error in statement syntax"));
1745 reg2 = 0;
1746 }
1747
1748 /* Check for spl registers. */
1749 if (check_spl_reg (&reg2))
1750 as_fatal (_("Cannot use special register with this instruction"));
1751
1752 inst |= (reg2 << RB_LOW) & RB_MASK;
1753 output = frag_more (isize);
1754 break;
1755
1756 case INST_TYPE_IMM:
1757 if (streq (name, "imm"))
1758 as_fatal (_("An IMM instruction should not be present in the .s file"));
1759
1760 op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1761
1762 if (exp.X_op != O_constant)
1763 {
1764 char *opc = NULL;
1765 relax_substateT subtype;
1766
69b06cc8
ME
1767 if (exp.X_md != 0)
1768 subtype = get_imm_otype(exp.X_md);
1769 else
1770 subtype = opcode->inst_offset_type;
1771
7ba29e2a
NC
1772 output = frag_var (rs_machine_dependent,
1773 isize * 2, /* maxm of 2 words. */
1774 isize, /* minm of 1 word. */
1775 subtype, /* PC-relative or not. */
1776 exp.X_add_symbol,
1777 exp.X_add_number,
1778 opc);
c7d6f518 1779 immed = 0;
7ba29e2a
NC
1780 }
1781 else
1782 {
1783 output = frag_more (isize);
c7d6f518 1784 immed = exp.X_add_number;
7ba29e2a
NC
1785 }
1786
1787
c7d6f518 1788 temp = immed & 0xFFFF8000;
7ba29e2a
NC
1789 if ((temp != 0) && (temp != 0xFFFF8000))
1790 {
1791 /* Needs an immediate inst. */
fe0e921f
AM
1792 opcode1
1793 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1794 "imm");
7ba29e2a
NC
1795 if (opcode1 == NULL)
1796 {
1797 as_bad (_("unknown opcode \"%s\""), "imm");
1798 return;
1799 }
1800
1801 inst1 = opcode1->bit_sequence;
c7d6f518 1802 inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
7ba29e2a
NC
1803 output[0] = INST_BYTE0 (inst1);
1804 output[1] = INST_BYTE1 (inst1);
1805 output[2] = INST_BYTE2 (inst1);
1806 output[3] = INST_BYTE3 (inst1);
1807 output = frag_more (isize);
1808 }
c7d6f518 1809 inst |= (immed << IMM_LOW) & IMM_MASK;
7ba29e2a
NC
1810 break;
1811
1812 case INST_TYPE_NONE:
1813 output = frag_more (isize);
1814 break;
1815
d3da7741
ME
1816 case INST_TYPE_IMM5:
1817 if (strcmp(op_end, ""))
1818 op_end = parse_imm (op_end + 1, & exp, MIN_IMM5, MAX_IMM5);
1819 else
1820 as_fatal(_("Error in statement syntax"));
1821 if (exp.X_op != O_constant) {
1822 as_warn(_("Symbol used as immediate for mbar instruction"));
1823 } else {
1824 output = frag_more (isize);
1825 immed = exp.X_add_number;
1826 }
1827 if (immed != (immed % 32)) {
1828 as_warn(_("Immediate value for mbar > 32. using <value %% 32>"));
1829 immed = immed % 32;
1830 }
1831 inst |= (immed << IMM_MBAR);
1832 break;
1833
7ba29e2a
NC
1834 default:
1835 as_fatal (_("unimplemented opcode \"%s\""), name);
1836 }
1837
1838 /* Drop whitespace after all the operands have been parsed. */
e23c5ac0 1839 while (ISSPACE (* op_end))
7ba29e2a
NC
1840 op_end ++;
1841
1842 /* Give warning message if the insn has more operands than required. */
1843 if (strcmp (op_end, opcode->name) && strcmp (op_end, ""))
1844 as_warn (_("ignoring operands: %s "), op_end);
1845
1846 output[0] = INST_BYTE0 (inst);
1847 output[1] = INST_BYTE1 (inst);
1848 output[2] = INST_BYTE2 (inst);
1849 output[3] = INST_BYTE3 (inst);
1850
1851#ifdef OBJ_ELF
1852 dwarf2_emit_insn (4);
1853#endif
1854}
1855
1856symbolS *
1857md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
1858{
1859 return NULL;
1860}
1861
7ba29e2a
NC
1862/* Turn a string in input_line_pointer into a floating point constant of type
1863 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1864 emitted is stored in *sizeP. An error message is returned, or NULL on OK.*/
3076e594 1865
6d4af3c2 1866const char *
7ba29e2a
NC
1867md_atof (int type, char * litP, int * sizeP)
1868{
1869 int prec;
1870 LITTLENUM_TYPE words[MAX_LITTLENUMS];
1871 int i;
1872 char * t;
1873
1874 switch (type)
1875 {
1876 case 'f':
1877 case 'F':
1878 case 's':
1879 case 'S':
1880 prec = 2;
1881 break;
1882
1883 case 'd':
1884 case 'D':
1885 case 'r':
1886 case 'R':
1887 prec = 4;
1888 break;
1889
1890 case 'x':
1891 case 'X':
1892 prec = 6;
1893 break;
1894
1895 case 'p':
1896 case 'P':
1897 prec = 6;
1898 break;
1899
1900 default:
1901 *sizeP = 0;
1902 return _("Bad call to MD_NTOF()");
1903 }
1904
1905 t = atof_ieee (input_line_pointer, type, words);
1906
1907 if (t)
1908 input_line_pointer = t;
1909
1910 *sizeP = prec * sizeof (LITTLENUM_TYPE);
1911
1912 if (! target_big_endian)
1913 {
1914 for (i = prec - 1; i >= 0; i--)
1915 {
1916 md_number_to_chars (litP, (valueT) words[i],
1917 sizeof (LITTLENUM_TYPE));
1918 litP += sizeof (LITTLENUM_TYPE);
1919 }
1920 }
1921 else
1922 for (i = 0; i < prec; i++)
1923 {
1924 md_number_to_chars (litP, (valueT) words[i],
1925 sizeof (LITTLENUM_TYPE));
1926 litP += sizeof (LITTLENUM_TYPE);
1927 }
1928
1929 return NULL;
1930}
1931\f
1932const char * md_shortopts = "";
1933
1934struct option md_longopts[] =
1935{
f23200ad
ME
1936 {"EB", no_argument, NULL, OPTION_EB},
1937 {"EL", no_argument, NULL, OPTION_EL},
1a64c359
ME
1938 {"mlittle-endian", no_argument, NULL, OPTION_EL},
1939 {"mbig-endian", no_argument, NULL, OPTION_EB},
7ba29e2a
NC
1940 { NULL, no_argument, NULL, 0}
1941};
1942
1943size_t md_longopts_size = sizeof (md_longopts);
1944
1945int md_short_jump_size;
1946
1947void
1948md_create_short_jump (char * ptr ATTRIBUTE_UNUSED,
1949 addressT from_Nddr ATTRIBUTE_UNUSED,
1950 addressT to_Nddr ATTRIBUTE_UNUSED,
1951 fragS * frag ATTRIBUTE_UNUSED,
1952 symbolS * to_symbol ATTRIBUTE_UNUSED)
1953{
1954 as_fatal (_("failed sanity check: short_jump"));
1955}
1956
1957void
1958md_create_long_jump (char * ptr ATTRIBUTE_UNUSED,
1959 addressT from_Nddr ATTRIBUTE_UNUSED,
1960 addressT to_Nddr ATTRIBUTE_UNUSED,
1961 fragS * frag ATTRIBUTE_UNUSED,
1962 symbolS * to_symbol ATTRIBUTE_UNUSED)
1963{
1964 as_fatal (_("failed sanity check: long_jump"));
1965}
1966
1967/* Called after relaxing, change the frags so they know how big they are. */
1968
1969void
1970md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
1971 segT sec ATTRIBUTE_UNUSED,
1972 fragS * fragP)
1973{
1974 fixS *fixP;
1975
1976 switch (fragP->fr_subtype)
1977 {
1978 case UNDEFINED_PC_OFFSET:
1979 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 1980 fragP->fr_offset, true, BFD_RELOC_64_PCREL);
7ba29e2a
NC
1981 fragP->fr_fix += INST_WORD_SIZE * 2;
1982 fragP->fr_var = 0;
1983 break;
1984 case DEFINED_ABS_SEGMENT:
1985 if (fragP->fr_symbol == GOT_symbol)
1986 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 1987 fragP->fr_offset, true, BFD_RELOC_MICROBLAZE_64_GOTPC);
7ba29e2a
NC
1988 else
1989 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 1990 fragP->fr_offset, false, BFD_RELOC_64);
7ba29e2a
NC
1991 fragP->fr_fix += INST_WORD_SIZE * 2;
1992 fragP->fr_var = 0;
1993 break;
1994 case DEFINED_RO_SEGMENT:
1995 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol,
5b7c81bd 1996 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_32_ROSDA);
7ba29e2a
NC
1997 fragP->fr_fix += INST_WORD_SIZE;
1998 fragP->fr_var = 0;
1999 break;
2000 case DEFINED_RW_SEGMENT:
2001 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol,
5b7c81bd 2002 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_32_RWSDA);
7ba29e2a
NC
2003 fragP->fr_fix += INST_WORD_SIZE;
2004 fragP->fr_var = 0;
2005 break;
2006 case DEFINED_PC_OFFSET:
2007 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol,
5b7c81bd 2008 fragP->fr_offset, true, BFD_RELOC_MICROBLAZE_32_LO_PCREL);
7ba29e2a
NC
2009 fragP->fr_fix += INST_WORD_SIZE;
2010 fragP->fr_var = 0;
2011 break;
2012 case LARGE_DEFINED_PC_OFFSET:
2013 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2014 fragP->fr_offset, true, BFD_RELOC_64_PCREL);
7ba29e2a
NC
2015 fragP->fr_fix += INST_WORD_SIZE * 2;
2016 fragP->fr_var = 0;
2017 break;
2018 case GOT_OFFSET:
2019 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2020 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_GOT);
7ba29e2a
NC
2021 fragP->fr_fix += INST_WORD_SIZE * 2;
2022 fragP->fr_var = 0;
2023 break;
3f0a5f17
ME
2024 case TEXT_OFFSET:
2025 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2026 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TEXTREL);
3f0a5f17
ME
2027 fragP->fr_fix += INST_WORD_SIZE * 2;
2028 fragP->fr_var = 0;
2029 break;
2030 case TEXT_PC_OFFSET:
2031 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2032 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TEXTPCREL);
3f0a5f17
ME
2033 fragP->fr_fix += INST_WORD_SIZE * 2;
2034 fragP->fr_var = 0;
2035 break;
7ba29e2a
NC
2036 case PLT_OFFSET:
2037 fixP = fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2038 fragP->fr_offset, true, BFD_RELOC_MICROBLAZE_64_PLT);
7ba29e2a 2039 /* fixP->fx_plt = 1; */
87975d2a 2040 (void) fixP;
7ba29e2a
NC
2041 fragP->fr_fix += INST_WORD_SIZE * 2;
2042 fragP->fr_var = 0;
2043 break;
2044 case GOTOFF_OFFSET:
2045 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2046 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_GOTOFF);
7ba29e2a
NC
2047 fragP->fr_fix += INST_WORD_SIZE * 2;
2048 fragP->fr_var = 0;
2049 break;
69b06cc8
ME
2050 case TLSGD_OFFSET:
2051 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2052 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TLSGD);
69b06cc8
ME
2053 fragP->fr_fix += INST_WORD_SIZE * 2;
2054 fragP->fr_var = 0;
2055 break;
2056 case TLSLD_OFFSET:
2057 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2058 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TLSLD);
69b06cc8
ME
2059 fragP->fr_fix += INST_WORD_SIZE * 2;
2060 fragP->fr_var = 0;
2061 break;
2062 case TLSDTPREL_OFFSET:
2063 fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
5b7c81bd 2064 fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TLSDTPREL);
69b06cc8
ME
2065 fragP->fr_fix += INST_WORD_SIZE * 2;
2066 fragP->fr_var = 0;
2067 break;
7ba29e2a
NC
2068
2069 default:
2070 abort ();
2071 }
2072}
2073
2074/* Applies the desired value to the specified location.
2075 Also sets up addends for 'rela' type relocations. */
2076void
2077md_apply_fix (fixS * fixP,
2078 valueT * valp,
2079 segT segment)
2080{
a39d29cd 2081 char * buf = fixP->fx_where + &fixP->fx_frag->fr_literal[0];
3b4dbbbf 2082 const char * file = fixP->fx_file ? fixP->fx_file : _("unknown");
7ba29e2a
NC
2083 const char * symname;
2084 /* Note: use offsetT because it is signed, valueT is unsigned. */
2085 offsetT val = (offsetT) * valp;
2086 int i;
2087 struct op_code_struct * opcode1;
2088 unsigned long inst1;
2089
2090 symname = fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : _("<unknown>");
2091
2092 /* fixP->fx_offset is supposed to be set up correctly for all
2093 symbol relocations. */
2094 if (fixP->fx_addsy == NULL)
2095 {
2096 if (!fixP->fx_pcrel)
2097 fixP->fx_offset = val; /* Absolute relocation. */
2098 else
2099 fprintf (stderr, "NULL symbol PC-relative relocation? offset = %08x, val = %08x\n",
2100 (unsigned int) fixP->fx_offset, (unsigned int) val);
2101 }
2102
2103 /* If we aren't adjusting this fixup to be against the section
2104 symbol, we need to adjust the value. */
2105 if (fixP->fx_addsy != NULL)
2106 {
2107 if (S_IS_WEAK (fixP->fx_addsy)
2108 || (symbol_used_in_reloc_p (fixP->fx_addsy)
fd361982 2109 && (((bfd_section_flags (S_GET_SEGMENT (fixP->fx_addsy))
7ba29e2a 2110 & SEC_LINK_ONCE) != 0)
d34049e8
ML
2111 || startswith (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
2112 ".gnu.linkonce"))))
7ba29e2a
NC
2113 {
2114 val -= S_GET_VALUE (fixP->fx_addsy);
2115 if (val != 0 && ! fixP->fx_pcrel)
2116 {
2117 /* In this case, the bfd_install_relocation routine will
2118 incorrectly add the symbol value back in. We just want
2119 the addend to appear in the object file.
2120 FIXME: If this makes VALUE zero, we're toast. */
2121 val -= S_GET_VALUE (fixP->fx_addsy);
2122 }
2123 }
2124 }
2125
2126 /* If the fix is relative to a symbol which is not defined, or not
2127 in the same segment as the fix, we cannot resolve it here. */
2128 /* fixP->fx_addsy is NULL if valp contains the entire relocation. */
2129 if (fixP->fx_addsy != NULL
2130 && (!S_IS_DEFINED (fixP->fx_addsy)
2131 || (S_GET_SEGMENT (fixP->fx_addsy) != segment)))
2132 {
2133 fixP->fx_done = 0;
2134#ifdef OBJ_ELF
2135 /* For ELF we can just return and let the reloc that will be generated
2136 take care of everything. For COFF we still have to insert 'val'
2137 into the insn since the addend field will be ignored. */
2138 /* return; */
2139#endif
2140 }
2141 /* All fixups in the text section must be handled in the linker. */
2142 else if (segment->flags & SEC_CODE)
2143 fixP->fx_done = 0;
2144 else if (!fixP->fx_pcrel && fixP->fx_addsy != NULL)
2145 fixP->fx_done = 0;
2146 else
2147 fixP->fx_done = 1;
2148
2149 switch (fixP->fx_r_type)
2150 {
2151 case BFD_RELOC_MICROBLAZE_32_LO:
2152 case BFD_RELOC_MICROBLAZE_32_LO_PCREL:
2153 if (target_big_endian)
2154 {
2155 buf[2] |= ((val >> 8) & 0xff);
2156 buf[3] |= (val & 0xff);
2157 }
2158 else
2159 {
2160 buf[1] |= ((val >> 8) & 0xff);
2161 buf[0] |= (val & 0xff);
2162 }
2163 break;
2164 case BFD_RELOC_MICROBLAZE_32_ROSDA:
2165 case BFD_RELOC_MICROBLAZE_32_RWSDA:
2166 /* Don't do anything if the symbol is not defined. */
2167 if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2168 {
2169 if (((val & 0xFFFF8000) != 0) && ((val & 0xFFFF8000) != 0xFFFF8000))
2170 as_bad_where (file, fixP->fx_line,
2171 _("pcrel for branch to %s too far (0x%x)"),
2172 symname, (int) val);
2173 if (target_big_endian)
2174 {
2175 buf[2] |= ((val >> 8) & 0xff);
2176 buf[3] |= (val & 0xff);
2177 }
2178 else
2179 {
2180 buf[1] |= ((val >> 8) & 0xff);
2181 buf[0] |= (val & 0xff);
2182 }
2183 }
2184 break;
2185 case BFD_RELOC_32:
2186 case BFD_RELOC_RVA:
2187 case BFD_RELOC_32_PCREL:
2188 case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM:
2189 /* Don't do anything if the symbol is not defined. */
2190 if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2191 {
2192 if (target_big_endian)
2193 {
2194 buf[0] |= ((val >> 24) & 0xff);
2195 buf[1] |= ((val >> 16) & 0xff);
2196 buf[2] |= ((val >> 8) & 0xff);
2197 buf[3] |= (val & 0xff);
2198 }
2199 else
2200 {
2201 buf[3] |= ((val >> 24) & 0xff);
2202 buf[2] |= ((val >> 16) & 0xff);
2203 buf[1] |= ((val >> 8) & 0xff);
2204 buf[0] |= (val & 0xff);
2205 }
2206 }
2207 break;
2208 case BFD_RELOC_64_PCREL:
2209 case BFD_RELOC_64:
3f0a5f17 2210 case BFD_RELOC_MICROBLAZE_64_TEXTREL:
7ba29e2a
NC
2211 /* Add an imm instruction. First save the current instruction. */
2212 for (i = 0; i < INST_WORD_SIZE; i++)
2213 buf[i + INST_WORD_SIZE] = buf[i];
2214
2215 /* Generate the imm instruction. */
fe0e921f
AM
2216 opcode1
2217 = (struct op_code_struct *) str_hash_find (opcode_hash_control, "imm");
7ba29e2a
NC
2218 if (opcode1 == NULL)
2219 {
2220 as_bad (_("unknown opcode \"%s\""), "imm");
2221 return;
2222 }
2223
2224 inst1 = opcode1->bit_sequence;
2225 if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2226 inst1 |= ((val & 0xFFFF0000) >> 16) & IMM_MASK;
2227
2228 buf[0] = INST_BYTE0 (inst1);
2229 buf[1] = INST_BYTE1 (inst1);
2230 buf[2] = INST_BYTE2 (inst1);
2231 buf[3] = INST_BYTE3 (inst1);
2232
2233 /* Add the value only if the symbol is defined. */
2234 if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2235 {
2236 if (target_big_endian)
2237 {
2238 buf[6] |= ((val >> 8) & 0xff);
2239 buf[7] |= (val & 0xff);
2240 }
2241 else
2242 {
2243 buf[5] |= ((val >> 8) & 0xff);
2244 buf[4] |= (val & 0xff);
2245 }
2246 }
2247 break;
2248
69b06cc8
ME
2249 case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
2250 case BFD_RELOC_MICROBLAZE_64_TLSGD:
2251 case BFD_RELOC_MICROBLAZE_64_TLSLD:
2252 S_SET_THREAD_LOCAL (fixP->fx_addsy);
1a0670f3 2253 /* Fall through. */
69b06cc8 2254
7ba29e2a
NC
2255 case BFD_RELOC_MICROBLAZE_64_GOTPC:
2256 case BFD_RELOC_MICROBLAZE_64_GOT:
2257 case BFD_RELOC_MICROBLAZE_64_PLT:
2258 case BFD_RELOC_MICROBLAZE_64_GOTOFF:
3f0a5f17 2259 case BFD_RELOC_MICROBLAZE_64_TEXTPCREL:
7ba29e2a
NC
2260 /* Add an imm instruction. First save the current instruction. */
2261 for (i = 0; i < INST_WORD_SIZE; i++)
2262 buf[i + INST_WORD_SIZE] = buf[i];
2263
2264 /* Generate the imm instruction. */
fe0e921f
AM
2265 opcode1
2266 = (struct op_code_struct *) str_hash_find (opcode_hash_control, "imm");
7ba29e2a
NC
2267 if (opcode1 == NULL)
2268 {
2269 as_bad (_("unknown opcode \"%s\""), "imm");
2270 return;
2271 }
2272
2273 inst1 = opcode1->bit_sequence;
2274
2275 /* We can fixup call to a defined non-global address
2276 within the same section only. */
2277 buf[0] = INST_BYTE0 (inst1);
2278 buf[1] = INST_BYTE1 (inst1);
2279 buf[2] = INST_BYTE2 (inst1);
2280 buf[3] = INST_BYTE3 (inst1);
2281 return;
2282
2283 default:
2284 break;
2285 }
2286
2287 if (fixP->fx_addsy == NULL)
2288 {
2289 /* This fixup has been resolved. Create a reloc in case the linker
2290 moves code around due to relaxing. */
2291 if (fixP->fx_r_type == BFD_RELOC_64_PCREL)
2292 fixP->fx_r_type = BFD_RELOC_MICROBLAZE_64_NONE;
d6053747
NF
2293 else if (fixP->fx_r_type == BFD_RELOC_32)
2294 fixP->fx_r_type = BFD_RELOC_MICROBLAZE_32_NONE;
7ba29e2a
NC
2295 else
2296 fixP->fx_r_type = BFD_RELOC_NONE;
2297 fixP->fx_addsy = section_symbol (absolute_section);
2298 }
2299 return;
2300}
2301
2302void
2303md_operand (expressionS * expressionP)
2304{
2305 /* Ignore leading hash symbol, if present. */
2306 if (*input_line_pointer == '#')
2307 {
2308 input_line_pointer ++;
2309 expression (expressionP);
2310 }
2311}
2312
2313/* Called just before address relaxation, return the length
2314 by which a fragment must grow to reach it's destination. */
2315
2316int
2317md_estimate_size_before_relax (fragS * fragP,
2318 segT segment_type)
2319{
2320 sbss_segment = bfd_get_section_by_name (stdoutput, ".sbss");
2321 sbss2_segment = bfd_get_section_by_name (stdoutput, ".sbss2");
2322 sdata_segment = bfd_get_section_by_name (stdoutput, ".sdata");
2323 sdata2_segment = bfd_get_section_by_name (stdoutput, ".sdata2");
2324
2325 switch (fragP->fr_subtype)
2326 {
2327 case INST_PC_OFFSET:
2328 /* Used to be a PC-relative branch. */
2329 if (!fragP->fr_symbol)
2330 {
2331 /* We know the abs value: Should never happen. */
2332 as_bad (_("Absolute PC-relative value in relaxation code. Assembler error....."));
2333 abort ();
2334 }
28ad2e2d
ME
2335 else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type &&
2336 !S_IS_WEAK (fragP->fr_symbol))
7ba29e2a
NC
2337 {
2338 fragP->fr_subtype = DEFINED_PC_OFFSET;
2339 /* Don't know now whether we need an imm instruction. */
2340 fragP->fr_var = INST_WORD_SIZE;
2341 }
2342 else if (S_IS_DEFINED (fragP->fr_symbol)
2343 && (((S_GET_SEGMENT (fragP->fr_symbol))->flags & SEC_CODE) == 0))
2344 {
2345 /* Cannot have a PC-relative branch to a diff segment. */
2346 as_bad (_("PC relative branch to label %s which is not in the instruction space"),
2347 S_GET_NAME (fragP->fr_symbol));
2348 fragP->fr_subtype = UNDEFINED_PC_OFFSET;
2349 fragP->fr_var = INST_WORD_SIZE*2;
2350 }
2351 else
2352 {
2353 fragP->fr_subtype = UNDEFINED_PC_OFFSET;
2354 fragP->fr_var = INST_WORD_SIZE*2;
2355 }
2356 break;
2357
2358 case INST_NO_OFFSET:
3f0a5f17 2359 case TEXT_OFFSET:
7ba29e2a
NC
2360 /* Used to be a reference to somewhere which was unknown. */
2361 if (fragP->fr_symbol)
2362 {
2363 if (fragP->fr_opcode == NULL)
2364 {
3f0a5f17
ME
2365 /* Used as an absolute value. */
2366 if (fragP->fr_subtype == INST_NO_OFFSET)
2367 fragP->fr_subtype = DEFINED_ABS_SEGMENT;
2368 /* Variable part does not change. */
2369 fragP->fr_var = INST_WORD_SIZE*2;
2370 }
7ba29e2a
NC
2371 else if (streq (fragP->fr_opcode, str_microblaze_ro_anchor))
2372 {
2373 /* It is accessed using the small data read only anchor. */
45dfa85a 2374 if ((S_GET_SEGMENT (fragP->fr_symbol) == bfd_com_section_ptr)
7ba29e2a
NC
2375 || (S_GET_SEGMENT (fragP->fr_symbol) == sdata2_segment)
2376 || (S_GET_SEGMENT (fragP->fr_symbol) == sbss2_segment)
2377 || (! S_IS_DEFINED (fragP->fr_symbol)))
2378 {
2379 fragP->fr_subtype = DEFINED_RO_SEGMENT;
2380 fragP->fr_var = INST_WORD_SIZE;
2381 }
2382 else
2383 {
2384 /* Variable not in small data read only segment accessed
2385 using small data read only anchor. */
3b4dbbbf 2386 const char *file = fragP->fr_file ? fragP->fr_file : _("unknown");
7ba29e2a
NC
2387
2388 as_bad_where (file, fragP->fr_line,
2389 _("Variable is accessed using small data read "
2390 "only anchor, but it is not in the small data "
2391 "read only section"));
2392 fragP->fr_subtype = DEFINED_RO_SEGMENT;
2393 fragP->fr_var = INST_WORD_SIZE;
2394 }
2395 }
2396 else if (streq (fragP->fr_opcode, str_microblaze_rw_anchor))
2397 {
45dfa85a 2398 if ((S_GET_SEGMENT (fragP->fr_symbol) == bfd_com_section_ptr)
7ba29e2a
NC
2399 || (S_GET_SEGMENT (fragP->fr_symbol) == sdata_segment)
2400 || (S_GET_SEGMENT (fragP->fr_symbol) == sbss_segment)
2401 || (!S_IS_DEFINED (fragP->fr_symbol)))
2402 {
2403 /* It is accessed using the small data read write anchor. */
2404 fragP->fr_subtype = DEFINED_RW_SEGMENT;
2405 fragP->fr_var = INST_WORD_SIZE;
2406 }
2407 else
2408 {
3b4dbbbf 2409 const char *file = fragP->fr_file ? fragP->fr_file : _("unknown");
7ba29e2a
NC
2410
2411 as_bad_where (file, fragP->fr_line,
2412 _("Variable is accessed using small data read "
2413 "write anchor, but it is not in the small data "
2414 "read write section"));
2415 fragP->fr_subtype = DEFINED_RW_SEGMENT;
2416 fragP->fr_var = INST_WORD_SIZE;
2417 }
2418 }
2419 else
2420 {
2421 as_bad (_("Incorrect fr_opcode value in frag. Internal error....."));
2422 abort ();
2423 }
2424 }
2425 else
2426 {
2427 /* We know the abs value: Should never happen. */
2428 as_bad (_("Absolute value in relaxation code. Assembler error....."));
2429 abort ();
2430 }
2431 break;
2432
2433 case UNDEFINED_PC_OFFSET:
2434 case LARGE_DEFINED_PC_OFFSET:
2435 case DEFINED_ABS_SEGMENT:
2436 case GOT_OFFSET:
2437 case PLT_OFFSET:
2438 case GOTOFF_OFFSET:
3f0a5f17 2439 case TEXT_PC_OFFSET:
69b06cc8
ME
2440 case TLSGD_OFFSET:
2441 case TLSLD_OFFSET:
2442 case TLSTPREL_OFFSET:
2443 case TLSDTPREL_OFFSET:
7ba29e2a
NC
2444 fragP->fr_var = INST_WORD_SIZE*2;
2445 break;
2446 case DEFINED_RO_SEGMENT:
2447 case DEFINED_RW_SEGMENT:
2448 case DEFINED_PC_OFFSET:
69b06cc8 2449 case TLSDTPMOD_OFFSET:
7ba29e2a
NC
2450 fragP->fr_var = INST_WORD_SIZE;
2451 break;
2452 default:
2453 abort ();
2454 }
2455
2456 return fragP->fr_var;
2457}
2458
2459/* Put number into target byte order. */
2460
2461void
2462md_number_to_chars (char * ptr, valueT use, int nbytes)
2463{
2464 if (target_big_endian)
2465 number_to_chars_bigendian (ptr, use, nbytes);
2466 else
2467 number_to_chars_littleendian (ptr, use, nbytes);
2468}
2469
2470/* Round up a section size to the appropriate boundary. */
2471
2472valueT
2473md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
2474{
2475 return size; /* Byte alignment is fine. */
2476}
2477
2478
2479/* The location from which a PC relative jump should be calculated,
2480 given a PC relative reloc. */
2481
2482long
2483md_pcrel_from_section (fixS * fixp, segT sec ATTRIBUTE_UNUSED)
2484{
2485#ifdef OBJ_ELF
2486 /* If the symbol is undefined or defined in another section
2487 we leave the add number alone for the linker to fix it later.
2488 Only account for the PC pre-bump (No PC-pre-bump on the Microblaze). */
2489
2490 if (fixp->fx_addsy != (symbolS *) NULL
2491 && (!S_IS_DEFINED (fixp->fx_addsy)
2492 || (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
2493 return 0;
2494 else
2495 {
2496 /* The case where we are going to resolve things... */
2497 if (fixp->fx_r_type == BFD_RELOC_64_PCREL)
2498 return fixp->fx_where + fixp->fx_frag->fr_address + INST_WORD_SIZE;
2499 else
2500 return fixp->fx_where + fixp->fx_frag->fr_address;
2501 }
2502#endif
2503}
2504
2505
2506#define F(SZ,PCREL) (((SZ) << 1) + (PCREL))
2507#define MAP(SZ,PCREL,TYPE) case F (SZ, PCREL): code = (TYPE); break
2508
2509arelent *
2510tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
2511{
2512 arelent * rel;
2513 bfd_reloc_code_real_type code;
2514
2515 switch (fixp->fx_r_type)
2516 {
2517 case BFD_RELOC_NONE:
d6053747 2518 case BFD_RELOC_MICROBLAZE_32_NONE:
7ba29e2a
NC
2519 case BFD_RELOC_MICROBLAZE_64_NONE:
2520 case BFD_RELOC_32:
2521 case BFD_RELOC_MICROBLAZE_32_LO:
2522 case BFD_RELOC_MICROBLAZE_32_LO_PCREL:
2523 case BFD_RELOC_RVA:
2524 case BFD_RELOC_64:
2525 case BFD_RELOC_64_PCREL:
2526 case BFD_RELOC_MICROBLAZE_32_ROSDA:
2527 case BFD_RELOC_MICROBLAZE_32_RWSDA:
2528 case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM:
2529 case BFD_RELOC_MICROBLAZE_64_GOTPC:
2530 case BFD_RELOC_MICROBLAZE_64_GOT:
2531 case BFD_RELOC_MICROBLAZE_64_PLT:
2532 case BFD_RELOC_MICROBLAZE_64_GOTOFF:
2533 case BFD_RELOC_MICROBLAZE_32_GOTOFF:
69b06cc8
ME
2534 case BFD_RELOC_MICROBLAZE_64_TLSGD:
2535 case BFD_RELOC_MICROBLAZE_64_TLSLD:
2536 case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD:
2537 case BFD_RELOC_MICROBLAZE_32_TLSDTPREL:
2538 case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
2539 case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL:
2540 case BFD_RELOC_MICROBLAZE_64_TLSTPREL:
3f0a5f17
ME
2541 case BFD_RELOC_MICROBLAZE_64_TEXTPCREL:
2542 case BFD_RELOC_MICROBLAZE_64_TEXTREL:
7ba29e2a
NC
2543 code = fixp->fx_r_type;
2544 break;
2545
2546 default:
2547 switch (F (fixp->fx_size, fixp->fx_pcrel))
2548 {
2549 MAP (1, 0, BFD_RELOC_8);
2550 MAP (2, 0, BFD_RELOC_16);
2551 MAP (4, 0, BFD_RELOC_32);
2552 MAP (1, 1, BFD_RELOC_8_PCREL);
2553 MAP (2, 1, BFD_RELOC_16_PCREL);
2554 MAP (4, 1, BFD_RELOC_32_PCREL);
2555 default:
2556 code = fixp->fx_r_type;
2557 as_bad (_("Can not do %d byte %srelocation"),
2558 fixp->fx_size,
33eaf5de 2559 fixp->fx_pcrel ? _("pc-relative ") : "");
7ba29e2a
NC
2560 }
2561 break;
2562 }
2563
add39d23
TS
2564 rel = XNEW (arelent);
2565 rel->sym_ptr_ptr = XNEW (asymbol *);
7ba29e2a
NC
2566
2567 if (code == BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM)
2568 *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
2569 else
2570 *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
2571
2572 rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
2573 /* Always pass the addend along! */
2574 rel->addend = fixp->fx_offset;
2575 rel->howto = bfd_reloc_type_lookup (stdoutput, code);
2576
2577 if (rel->howto == NULL)
2578 {
2579 as_bad_where (fixp->fx_file, fixp->fx_line,
2580 _("Cannot represent relocation type %s"),
2581 bfd_get_reloc_code_name (code));
2582
2583 /* Set howto to a garbage value so that we can keep going. */
2584 rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
2585 gas_assert (rel->howto != NULL);
2586 }
2587 return rel;
2588}
2589
2590int
17b9d67d 2591md_parse_option (int c, const char * arg ATTRIBUTE_UNUSED)
7ba29e2a
NC
2592{
2593 switch (c)
2594 {
f23200ad
ME
2595 case OPTION_EB:
2596 target_big_endian = 1;
2597 break;
2598 case OPTION_EL:
2599 target_big_endian = 0;
2600 break;
7ba29e2a
NC
2601 default:
2602 return 0;
2603 }
2604 return 1;
2605}
2606
2607void
2608md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
2609{
2610 /* fprintf(stream, _("\
2611 MicroBlaze options:\n\
2612 -noSmall Data in the comm and data sections do not go into the small data section\n")); */
1a64c359
ME
2613 fprintf (stream, _(" MicroBlaze specific assembler options:\n"));
2614 fprintf (stream, " -%-23s%s\n", "mbig-endian", N_("assemble for a big endian cpu"));
2615 fprintf (stream, " -%-23s%s\n", "mlittle-endian", N_("assemble for a little endian cpu"));
7ba29e2a
NC
2616}
2617
2618
2619/* Create a fixup for a cons expression. If parse_cons_expression_microblaze
2620 found a machine specific op in an expression,
2621 then we create relocs accordingly. */
2622
2623void
2624cons_fix_new_microblaze (fragS * frag,
2625 int where,
2626 int size,
62ebcb5c
AM
2627 expressionS *exp,
2628 bfd_reloc_code_real_type r)
7ba29e2a 2629{
7ba29e2a
NC
2630 if ((exp->X_op == O_subtract) && (exp->X_add_symbol) &&
2631 (exp->X_op_symbol) && (now_seg != absolute_section) && (size == 4)
2632 && (!S_IS_LOCAL (exp->X_op_symbol)))
2633 r = BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM;
2634 else if (exp->X_md == IMM_GOTOFF && exp->X_op == O_symbol_rva)
2635 {
2636 exp->X_op = O_symbol;
2637 r = BFD_RELOC_MICROBLAZE_32_GOTOFF;
2638 }
2639 else
2640 {
2641 switch (size)
2642 {
2643 case 1:
2644 r = BFD_RELOC_8;
2645 break;
2646 case 2:
2647 r = BFD_RELOC_16;
2648 break;
2649 case 4:
2650 r = BFD_RELOC_32;
2651 break;
2652 case 8:
2653 r = BFD_RELOC_64;
2654 break;
2655 default:
2656 as_bad (_("unsupported BFD relocation size %u"), size);
2657 r = BFD_RELOC_32;
2658 break;
2659 }
2660 }
2661 fix_new_exp (frag, where, size, exp, 0, r);
2662}