Port gas/config/* to str_htab.
[deliverable/binutils-gdb.git] / gas / config / tc-spu.c
CommitLineData
e9f53129
AM
1/* spu.c -- Assembler for the IBM Synergistic Processing Unit (SPU)
2
b3adc24a 3 Copyright (C) 2006-2020 Free Software Foundation, Inc.
e9f53129
AM
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
ec2655a6 9 the Free Software Foundation; either version 3, or (at your option)
e9f53129
AM
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
22#include "as.h"
23#include "safe-ctype.h"
24#include "subsegs.h"
3739860c 25#include "dwarf2dbg.h"
e9f53129
AM
26
27const struct spu_opcode spu_opcodes[] = {
28#define APUOP(TAG,MACFORMAT,OPCODE,MNEMONIC,ASMFORMAT,DEP,PIPE) \
2900e701 29 { MACFORMAT, (OPCODE ## u) << (32-11), MNEMONIC, ASMFORMAT },
e9f53129
AM
30#define APUOPFB(TAG,MACFORMAT,OPCODE,FB,MNEMONIC,ASMFORMAT,DEP,PIPE) \
31 { MACFORMAT, ((OPCODE) << (32-11)) | ((FB) << (32-18)), MNEMONIC, ASMFORMAT },
32#include "opcode/spu-insns.h"
33#undef APUOP
34#undef APUOPFB
35};
36
37static const int spu_num_opcodes =
38 sizeof (spu_opcodes) / sizeof (spu_opcodes[0]);
39
40#define MAX_RELOCS 2
41
42struct spu_insn
43{
44 unsigned int opcode;
45 expressionS exp[MAX_RELOCS];
46 int reloc_arg[MAX_RELOCS];
7bc3e93c 47 bfd_reloc_code_real_type reloc[MAX_RELOCS];
e9f53129
AM
48 enum spu_insns tag;
49};
50
51static const char *get_imm (const char *param, struct spu_insn *insn, int arg);
52static const char *get_reg (const char *param, struct spu_insn *insn, int arg,
53 int accept_expr);
e9f53129
AM
54static int calcop (struct spu_opcode *format, const char *param,
55 struct spu_insn *insn);
cd4a7468 56static void spu_brinfo (int);
ece5ef60 57static void spu_cons (int);
e9f53129
AM
58
59extern char *myname;
629310ab 60static htab_t op_hash = NULL;
e9f53129
AM
61
62/* These bits should be turned off in the first address of every segment */
63int md_seg_align = 7;
64
65/* These chars start a comment anywhere in a source file (except inside
66 another comment */
67const char comment_chars[] = "#";
68
69/* These chars only start a comment at the beginning of a line. */
70const char line_comment_chars[] = "#";
71
72/* gods own line continuation char */
73const char line_separator_chars[] = ";";
74
75/* Chars that can be used to separate mant from exp in floating point nums */
76const char EXP_CHARS[] = "eE";
77
78/* Chars that mean this number is a floating point constant */
79/* as in 0f123.456 */
80/* or 0H1.234E-12 (see exp chars above) */
81const char FLT_CHARS[] = "dDfF";
82
83const pseudo_typeS md_pseudo_table[] =
84{
85 {"align", s_align_ptwo, 4},
cd4a7468 86 {"brinfo", spu_brinfo, 0},
ece5ef60 87 {"bss", s_lcomm_bytes, 1},
e9f53129
AM
88 {"def", s_set, 0},
89 {"dfloat", float_cons, 'd'},
90 {"ffloat", float_cons, 'f'},
91 {"global", s_globl, 0},
92 {"half", cons, 2},
ece5ef60
AM
93 {"int", spu_cons, 4},
94 {"long", spu_cons, 4},
95 {"quad", spu_cons, 8},
38a57ae7 96 {"string", stringer, 8 + 1},
ece5ef60 97 {"word", spu_cons, 4},
e9f53129
AM
98 /* Force set to be treated as an instruction. */
99 {"set", NULL, 0},
100 {".set", s_set, 0},
cefdba39
AM
101 /* Likewise for eqv. */
102 {"eqv", NULL, 0},
103 {".eqv", s_set, -1},
e9f53129
AM
104 {0,0,0}
105};
106
cd4a7468
AM
107/* Bits plugged into branch instruction offset field. */
108unsigned int brinfo;
109
e9f53129
AM
110void
111md_begin (void)
112{
e9f53129
AM
113 int i;
114
115 /* initialize hash table */
116
629310ab 117 op_hash = str_htab_create ();
e9f53129
AM
118
119 /* loop until you see the end of the list */
120
121 for (i = 0; i < spu_num_opcodes; i++)
629310ab
ML
122 /* hash each mnemonic and record its position */
123 if (str_hash_find (op_hash, spu_opcodes[i].mnemonic) == NULL)
124 str_hash_insert (op_hash, spu_opcodes[i].mnemonic,
125 (void *) &spu_opcodes[i]);
e9f53129
AM
126}
127\f
128const char *md_shortopts = "";
129struct option md_longopts[] = {
130#define OPTION_APUASM (OPTION_MD_BASE)
131 {"apuasm", no_argument, NULL, OPTION_APUASM},
132#define OPTION_DD2 (OPTION_MD_BASE+1)
133 {"mdd2.0", no_argument, NULL, OPTION_DD2},
134#define OPTION_DD1 (OPTION_MD_BASE+2)
135 {"mdd1.0", no_argument, NULL, OPTION_DD1},
136#define OPTION_DD3 (OPTION_MD_BASE+3)
137 {"mdd3.0", no_argument, NULL, OPTION_DD3},
138 { NULL, no_argument, NULL, 0 }
139};
140size_t md_longopts_size = sizeof (md_longopts);
141
142/* When set (by -apuasm) our assembler emulates the behaviour of apuasm.
143 * e.g. don't add bias to float conversion and don't right shift
144 * immediate values. */
145static int emulate_apuasm;
146
147/* Use the dd2.0 instructions set. The only differences are some new
148 * register names and the orx insn */
149static int use_dd2 = 1;
150
151int
17b9d67d 152md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
e9f53129
AM
153{
154 switch (c)
155 {
156 case OPTION_APUASM:
157 emulate_apuasm = 1;
158 break;
159 case OPTION_DD3:
160 use_dd2 = 1;
161 break;
162 case OPTION_DD2:
163 use_dd2 = 1;
164 break;
165 case OPTION_DD1:
166 use_dd2 = 0;
167 break;
168 default:
169 return 0;
170 }
171 return 1;
172}
173
174void
175md_show_usage (FILE *stream)
176{
177 fputs (_("\
178SPU options:\n\
179 --apuasm emulate behaviour of apuasm\n"),
180 stream);
181}
182\f
183
184struct arg_encode {
185 int size;
186 int pos;
187 int rshift;
188 int lo, hi;
189 int wlo, whi;
190 bfd_reloc_code_real_type reloc;
191};
192
193static struct arg_encode arg_encode[A_MAX] = {
194 { 7, 0, 0, 0, 127, 0, -1, 0 }, /* A_T */
195 { 7, 7, 0, 0, 127, 0, -1, 0 }, /* A_A */
196 { 7, 14, 0, 0, 127, 0, -1, 0 }, /* A_B */
197 { 7, 21, 0, 0, 127, 0, -1, 0 }, /* A_C */
198 { 7, 7, 0, 0, 127, 0, -1, 0 }, /* A_S */
199 { 7, 7, 0, 0, 127, 0, -1, 0 }, /* A_H */
200 { 0, 0, 0, 0, -1, 0, -1, 0 }, /* A_P */
201 { 7, 14, 0, 0, -1, 0, -1, BFD_RELOC_SPU_IMM7 }, /* A_S3 */
202 { 7, 14, 0, -32, 31, -31, 0, BFD_RELOC_SPU_IMM7 }, /* A_S6 */
203 { 7, 14, 0, 0, -1, 0, -1, BFD_RELOC_SPU_IMM7 }, /* A_S7N */
204 { 7, 14, 0, -64, 63, -63, 0, BFD_RELOC_SPU_IMM7 }, /* A_S7 */
205 { 8, 14, 0, 0, 127, 0, -1, BFD_RELOC_SPU_IMM8 }, /* A_U7A */
206 { 8, 14, 0, 0, 127, 0, -1, BFD_RELOC_SPU_IMM8 }, /* A_U7B */
207 { 10, 14, 0, -512, 511, -128, 255, BFD_RELOC_SPU_IMM10 }, /* A_S10B */
208 { 10, 14, 0, -512, 511, 0, -1, BFD_RELOC_SPU_IMM10 }, /* A_S10 */
209 { 2, 23, 9, -1024, 1023, 0, -1, BFD_RELOC_SPU_PCREL9a }, /* A_S11 */
210 { 2, 14, 9, -1024, 1023, 0, -1, BFD_RELOC_SPU_PCREL9b }, /* A_S11I */
211 { 10, 14, 4, -8192, 8191, 0, -1, BFD_RELOC_SPU_IMM10W }, /* A_S14 */
212 { 16, 7, 0, -32768, 32767, 0, -1, BFD_RELOC_SPU_IMM16 }, /* A_S16 */
213 { 16, 7, 2, -131072, 262143, 0, -1, BFD_RELOC_SPU_IMM16W }, /* A_S18 */
214 { 16, 7, 2, -262144, 262143, 0, -1, BFD_RELOC_SPU_PCREL16 }, /* A_R18 */
215 { 7, 14, 0, 0, -1, 0, -1, BFD_RELOC_SPU_IMM7 }, /* A_U3 */
216 { 7, 14, 0, 0, 127, 0, 31, BFD_RELOC_SPU_IMM7 }, /* A_U5 */
217 { 7, 14, 0, 0, 127, 0, 63, BFD_RELOC_SPU_IMM7 }, /* A_U6 */
218 { 7, 14, 0, 0, -1, 0, -1, BFD_RELOC_SPU_IMM7 }, /* A_U7 */
219 { 14, 0, 0, 0, 16383, 0, -1, 0 }, /* A_U14 */
220 { 16, 7, 0, -32768, 65535, 0, -1, BFD_RELOC_SPU_IMM16 }, /* A_X16 */
221 { 18, 7, 0, 0, 262143, 0, -1, BFD_RELOC_SPU_IMM18 }, /* A_U18 */
222};
223
224/* Some flags for handling errors. This is very hackish and added after
225 * the fact. */
226static int syntax_error_arg;
227static const char *syntax_error_param;
228static int syntax_reg;
229
230static char *
231insn_fmt_string (struct spu_opcode *format)
232{
233 static char buf[64];
234 int len = 0;
235 int i;
236
237 len += sprintf (&buf[len], "%s\t", format->mnemonic);
238 for (i = 1; i <= format->arg[0]; i++)
239 {
240 int arg = format->arg[i];
e0471c16 241 const char *exp;
3739860c 242 if (i > 1 && arg != A_P && format->arg[i-1] != A_P)
e9f53129
AM
243 buf[len++] = ',';
244 if (arg == A_P)
245 exp = "(";
246 else if (arg < A_P)
247 exp = i == syntax_error_arg ? "REG" : "reg";
3739860c 248 else
e9f53129
AM
249 exp = i == syntax_error_arg ? "IMM" : "imm";
250 len += sprintf (&buf[len], "%s", exp);
3739860c 251 if (i > 1 && format->arg[i-1] == A_P)
e9f53129
AM
252 buf[len++] = ')';
253 }
254 buf[len] = 0;
255 return buf;
256}
257
258void
259md_assemble (char *op)
260{
261 char *param, *thisfrag;
262 char c;
263 struct spu_opcode *format;
264 struct spu_insn insn;
265 int i;
266
9c2799c2 267 gas_assert (op);
e9f53129
AM
268
269 /* skip over instruction to find parameters */
270
271 for (param = op; *param != 0 && !ISSPACE (*param); param++)
272 ;
273 c = *param;
274 *param = 0;
275
276 if (c != 0 && c != '\n')
277 param++;
278
279 /* try to find the instruction in the hash table */
280
629310ab 281 if ((format = (struct spu_opcode *) str_hash_find (op_hash, op)) == NULL)
e9f53129
AM
282 {
283 as_bad (_("Invalid mnemonic '%s'"), op);
284 return;
285 }
286
287 if (!use_dd2 && strcmp (format->mnemonic, "orx") == 0)
288 {
289 as_bad (_("'%s' is only available in DD2.0 or higher."), op);
290 return;
291 }
292
293 while (1)
294 {
295 /* try parsing this instruction into insn */
296 for (i = 0; i < MAX_RELOCS; i++)
297 {
298 insn.exp[i].X_add_symbol = 0;
299 insn.exp[i].X_op_symbol = 0;
300 insn.exp[i].X_add_number = 0;
301 insn.exp[i].X_op = O_illegal;
302 insn.reloc_arg[i] = -1;
7bc3e93c 303 insn.reloc[i] = BFD_RELOC_NONE;
e9f53129
AM
304 }
305 insn.opcode = format->opcode;
306 insn.tag = (enum spu_insns) (format - spu_opcodes);
307
308 syntax_error_arg = 0;
309 syntax_error_param = 0;
310 syntax_reg = 0;
311 if (calcop (format, param, &insn))
312 break;
313
314 /* if it doesn't parse try the next instruction */
315 if (!strcmp (format[0].mnemonic, format[1].mnemonic))
316 format++;
317 else
318 {
319 int parg = format[0].arg[syntax_error_arg-1];
320
321 as_fatal (_("Error in argument %d. Expecting: \"%s\""),
322 syntax_error_arg - (parg == A_P),
323 insn_fmt_string (format));
324 return;
325 }
326 }
327
328 if ((syntax_reg & 4)
329 && ! (insn.tag == M_RDCH
330 || insn.tag == M_RCHCNT
331 || insn.tag == M_WRCH))
332 as_warn (_("Mixing register syntax, with and without '$'."));
333 if (syntax_error_param)
334 {
335 const char *d = syntax_error_param;
336 while (*d != '$')
337 d--;
e2785c44 338 as_warn (_("Treating '%-*s' as a symbol."), (int)(syntax_error_param - d), d);
e9f53129
AM
339 }
340
cd4a7468
AM
341 if (brinfo != 0
342 && (insn.tag <= M_BRASL
343 || (insn.tag >= M_BRZ && insn.tag <= M_BRHNZ))
344 && (insn.opcode & 0x7ff80) == 0
345 && (insn.reloc_arg[0] == A_R18
346 || insn.reloc_arg[0] == A_S18
347 || insn.reloc_arg[1] == A_R18
348 || insn.reloc_arg[1] == A_S18))
349 insn.opcode |= brinfo << 7;
350
e9f53129
AM
351 /* grow the current frag and plop in the opcode */
352
353 thisfrag = frag_more (4);
354 md_number_to_chars (thisfrag, insn.opcode, 4);
355
356 /* if this instruction requires labels mark it for later */
357
358 for (i = 0; i < MAX_RELOCS; i++)
3739860c 359 if (insn.reloc_arg[i] >= 0)
e9f53129
AM
360 {
361 fixS *fixP;
7bc3e93c 362 bfd_reloc_code_real_type reloc = insn.reloc[i];
e9f53129 363 int pcrel = 0;
ece5ef60 364
7bc3e93c 365 if (reloc == BFD_RELOC_SPU_PCREL9a
e9f53129 366 || reloc == BFD_RELOC_SPU_PCREL9b
7bc3e93c 367 || reloc == BFD_RELOC_SPU_PCREL16)
e9f53129 368 pcrel = 1;
e9f53129
AM
369 fixP = fix_new_exp (frag_now,
370 thisfrag - frag_now->fr_literal,
371 4,
372 &insn.exp[i],
373 pcrel,
374 reloc);
840edabd
AM
375 fixP->tc_fix_data.arg_format = insn.reloc_arg[i];
376 fixP->tc_fix_data.insn_tag = insn.tag;
e9f53129
AM
377 }
378 dwarf2_emit_insn (4);
cd4a7468
AM
379
380 /* .brinfo lasts exactly one instruction. */
381 brinfo = 0;
e9f53129
AM
382}
383
384static int
385calcop (struct spu_opcode *format, const char *param, struct spu_insn *insn)
386{
387 int i;
388 int paren = 0;
389 int arg;
390
391 for (i = 1; i <= format->arg[0]; i++)
392 {
393 arg = format->arg[i];
394 syntax_error_arg = i;
395
396 while (ISSPACE (*param))
397 param++;
398 if (*param == 0 || *param == ',')
399 return 0;
400 if (arg < A_P)
401 param = get_reg (param, insn, arg, 1);
402 else if (arg > A_P)
7bc3e93c 403 param = get_imm (param, insn, arg);
e9f53129
AM
404 else if (arg == A_P)
405 {
406 paren++;
407 if ('(' != *param++)
408 return 0;
409 }
410
411 if (!param)
412 return 0;
413
414 while (ISSPACE (*param))
415 param++;
416
417 if (arg != A_P && paren)
418 {
419 paren--;
420 if (')' != *param++)
421 return 0;
422 }
423 else if (i < format->arg[0]
424 && format->arg[i] != A_P
425 && format->arg[i+1] != A_P)
426 {
427 if (',' != *param++)
428 {
429 syntax_error_arg++;
430 return 0;
431 }
432 }
433 }
434 while (ISSPACE (*param))
435 param++;
436 return !paren && (*param == 0 || *param == '\n');
437}
438
439struct reg_name {
440 unsigned int regno;
441 unsigned int length;
442 char name[32];
443};
444
445#define REG_NAME(NO,NM) { NO, sizeof (NM) - 1, NM }
446
447static struct reg_name reg_name[] = {
448 REG_NAME (0, "lr"), /* link register */
449 REG_NAME (1, "sp"), /* stack pointer */
450 REG_NAME (0, "rp"), /* link register */
451 REG_NAME (127, "fp"), /* frame pointer */
452};
453
454static struct reg_name sp_reg_name[] = {
455};
456
457static struct reg_name ch_reg_name[] = {
458 REG_NAME ( 0, "SPU_RdEventStat"),
459 REG_NAME ( 1, "SPU_WrEventMask"),
460 REG_NAME ( 2, "SPU_WrEventAck"),
461 REG_NAME ( 3, "SPU_RdSigNotify1"),
462 REG_NAME ( 4, "SPU_RdSigNotify2"),
463 REG_NAME ( 7, "SPU_WrDec"),
464 REG_NAME ( 8, "SPU_RdDec"),
465 REG_NAME ( 11, "SPU_RdEventMask"), /* DD2.0 only */
466 REG_NAME ( 13, "SPU_RdMachStat"),
467 REG_NAME ( 14, "SPU_WrSRR0"),
468 REG_NAME ( 15, "SPU_RdSRR0"),
469 REG_NAME ( 28, "SPU_WrOutMbox"),
470 REG_NAME ( 29, "SPU_RdInMbox"),
471 REG_NAME ( 30, "SPU_WrOutIntrMbox"),
472 REG_NAME ( 9, "MFC_WrMSSyncReq"),
473 REG_NAME ( 12, "MFC_RdTagMask"), /* DD2.0 only */
474 REG_NAME ( 16, "MFC_LSA"),
475 REG_NAME ( 17, "MFC_EAH"),
476 REG_NAME ( 18, "MFC_EAL"),
477 REG_NAME ( 19, "MFC_Size"),
478 REG_NAME ( 20, "MFC_TagID"),
479 REG_NAME ( 21, "MFC_Cmd"),
480 REG_NAME ( 22, "MFC_WrTagMask"),
481 REG_NAME ( 23, "MFC_WrTagUpdate"),
482 REG_NAME ( 24, "MFC_RdTagStat"),
483 REG_NAME ( 25, "MFC_RdListStallStat"),
484 REG_NAME ( 26, "MFC_WrListStallAck"),
485 REG_NAME ( 27, "MFC_RdAtomicStat"),
486};
487#undef REG_NAME
488
489static const char *
490get_reg (const char *param, struct spu_insn *insn, int arg, int accept_expr)
491{
492 unsigned regno;
493 int saw_prefix = 0;
494
495 if (*param == '$')
496 {
497 saw_prefix = 1;
498 param++;
499 }
3739860c 500
e9f53129
AM
501 if (arg == A_H) /* Channel */
502 {
503 if ((param[0] == 'c' || param[0] == 'C')
504 && (param[1] == 'h' || param[1] == 'H')
505 && ISDIGIT (param[2]))
506 param += 2;
507 }
508 else if (arg == A_S) /* Special purpose register */
509 {
510 if ((param[0] == 's' || param[0] == 'S')
511 && (param[1] == 'p' || param[1] == 'P')
512 && ISDIGIT (param[2]))
513 param += 2;
514 }
515
516 if (ISDIGIT (*param))
517 {
518 regno = 0;
519 while (ISDIGIT (*param))
520 regno = regno * 10 + *param++ - '0';
521 }
522 else
523 {
524 struct reg_name *rn;
525 unsigned int i, n, l = 0;
526
527 if (arg == A_H) /* Channel */
528 {
529 rn = ch_reg_name;
530 n = sizeof (ch_reg_name) / sizeof (*ch_reg_name);
531 }
532 else if (arg == A_S) /* Special purpose register */
533 {
534 rn = sp_reg_name;
535 n = sizeof (sp_reg_name) / sizeof (*sp_reg_name);
536 }
537 else
538 {
539 rn = reg_name;
540 n = sizeof (reg_name) / sizeof (*reg_name);
541 }
542 regno = 128;
543 for (i = 0; i < n; i++)
544 if (rn[i].length > l
545 && 0 == strncasecmp (param, rn[i].name, rn[i].length))
546 {
547 l = rn[i].length;
548 regno = rn[i].regno;
549 }
550 param += l;
551 }
552
553 if (!use_dd2
554 && arg == A_H)
555 {
556 if (regno == 11)
557 as_bad (_("'SPU_RdEventMask' (channel 11) is only available in DD2.0 or higher."));
558 else if (regno == 12)
559 as_bad (_("'MFC_RdTagMask' (channel 12) is only available in DD2.0 or higher."));
560 }
561
562 if (regno < 128)
563 {
564 insn->opcode |= regno << arg_encode[arg].pos;
565 if ((!saw_prefix && syntax_reg == 1)
566 || (saw_prefix && syntax_reg == 2))
567 syntax_reg |= 4;
568 syntax_reg |= saw_prefix ? 1 : 2;
569 return param;
570 }
571
572 if (accept_expr)
573 {
574 char *save_ptr;
575 expressionS ex;
576 save_ptr = input_line_pointer;
577 input_line_pointer = (char *)param;
578 expression (&ex);
579 param = input_line_pointer;
580 input_line_pointer = save_ptr;
581 if (ex.X_op == O_register || ex.X_op == O_constant)
582 {
583 insn->opcode |= ex.X_add_number << arg_encode[arg].pos;
584 return param;
585 }
586 }
587 return 0;
588}
589
590static const char *
591get_imm (const char *param, struct spu_insn *insn, int arg)
592{
593 int val;
594 char *save_ptr;
595 int low = 0, high = 0;
596 int reloc_i = insn->reloc_arg[0] >= 0 ? 1 : 0;
597
ece5ef60 598 if (strncasecmp (param, "%lo(", 4) == 0)
e9f53129
AM
599 {
600 param += 3;
601 low = 1;
602 as_warn (_("Using old style, %%lo(expr), please change to PPC style, expr@l."));
603 }
ece5ef60 604 else if (strncasecmp (param, "%hi(", 4) == 0)
e9f53129
AM
605 {
606 param += 3;
607 high = 1;
608 as_warn (_("Using old style, %%hi(expr), please change to PPC style, expr@h."));
609 }
ece5ef60 610 else if (strncasecmp (param, "%pic(", 5) == 0)
e9f53129
AM
611 {
612 /* Currently we expect %pic(expr) == expr, so do nothing here.
ece5ef60 613 i.e. for code loaded at address 0 $toc will be 0. */
e9f53129
AM
614 param += 4;
615 }
3739860c 616
e9f53129
AM
617 if (*param == '$')
618 {
619 /* Symbols can start with $, but if this symbol matches a register
ece5ef60
AM
620 name, it's probably a mistake. The only way to avoid this
621 warning is to rename the symbol. */
e9f53129
AM
622 struct spu_insn tmp_insn;
623 const char *np = get_reg (param, &tmp_insn, arg, 0);
624
625 if (np)
626 syntax_error_param = np;
627 }
3739860c 628
e9f53129
AM
629 save_ptr = input_line_pointer;
630 input_line_pointer = (char *) param;
631 expression (&insn->exp[reloc_i]);
632 param = input_line_pointer;
633 input_line_pointer = save_ptr;
634
635 /* Similar to ppc_elf_suffix in tc-ppc.c. We have so few cases to
ece5ef60 636 handle we do it inlined here. */
e9f53129
AM
637 if (param[0] == '@' && !ISALNUM (param[2]) && param[2] != '@')
638 {
639 if (param[1] == 'h' || param[1] == 'H')
640 {
641 high = 1;
642 param += 2;
643 }
644 else if (param[1] == 'l' || param[1] == 'L')
645 {
646 low = 1;
647 param += 2;
648 }
649 }
650
e9f53129
AM
651 if (insn->exp[reloc_i].X_op == O_constant)
652 {
ece5ef60
AM
653 val = insn->exp[reloc_i].X_add_number;
654
e9f53129
AM
655 if (emulate_apuasm)
656 {
3739860c 657 /* Convert the value to a format we expect. */
e9f53129
AM
658 val <<= arg_encode[arg].rshift;
659 if (arg == A_U7A)
660 val = 173 - val;
661 else if (arg == A_U7B)
3739860c 662 val = 155 - val;
e9f53129
AM
663 }
664
665 if (high)
666 val = val >> 16;
667 else if (low)
668 val = val & 0xffff;
669
670 /* Warn about out of range expressions. */
671 {
672 int hi = arg_encode[arg].hi;
673 int lo = arg_encode[arg].lo;
674 int whi = arg_encode[arg].whi;
675 int wlo = arg_encode[arg].wlo;
676
677 if (hi > lo && (val < lo || val > hi))
678 as_fatal (_("Constant expression %d out of range, [%d, %d]."),
679 val, lo, hi);
680 else if (whi > wlo && (val < wlo || val > whi))
681 as_warn (_("Constant expression %d out of range, [%d, %d]."),
682 val, wlo, whi);
683 }
684
685 if (arg == A_U7A)
686 val = 173 - val;
687 else if (arg == A_U7B)
3739860c 688 val = 155 - val;
e9f53129
AM
689
690 /* Branch hints have a split encoding. Do the bottom part. */
691 if (arg == A_S11 || arg == A_S11I)
692 insn->opcode |= ((val >> 2) & 0x7f);
693
694 insn->opcode |= (((val >> arg_encode[arg].rshift)
695 & ((1 << arg_encode[arg].size) - 1))
696 << arg_encode[arg].pos);
e9f53129
AM
697 }
698 else
699 {
700 insn->reloc_arg[reloc_i] = arg;
701 if (high)
7bc3e93c 702 insn->reloc[reloc_i] = BFD_RELOC_SPU_HI16;
ece5ef60 703 else if (low)
7bc3e93c
AM
704 insn->reloc[reloc_i] = BFD_RELOC_SPU_LO16;
705 else
706 insn->reloc[reloc_i] = arg_encode[arg].reloc;
e9f53129
AM
707 }
708
709 return param;
710}
711
6d4af3c2 712const char *
e9f53129
AM
713md_atof (int type, char *litP, int *sizeP)
714{
499ac353 715 return ieee_md_atof (type, litP, sizeP, TRUE);
e9f53129
AM
716}
717
718#ifndef WORKING_DOT_WORD
719int md_short_jump_size = 4;
720
721void
722md_create_short_jump (char *ptr,
723 addressT from_addr ATTRIBUTE_UNUSED,
724 addressT to_addr ATTRIBUTE_UNUSED,
725 fragS *frag,
726 symbolS *to_symbol)
727{
728 ptr[0] = (char) 0xc0;
729 ptr[1] = 0x00;
730 ptr[2] = 0x00;
731 ptr[3] = 0x00;
732 fix_new (frag,
733 ptr - frag->fr_literal,
734 4,
735 to_symbol,
736 (offsetT) 0,
737 0,
738 BFD_RELOC_SPU_PCREL16);
739}
740
741int md_long_jump_size = 4;
742
743void
744md_create_long_jump (char *ptr,
745 addressT from_addr ATTRIBUTE_UNUSED,
746 addressT to_addr ATTRIBUTE_UNUSED,
747 fragS *frag,
748 symbolS *to_symbol)
749{
750 ptr[0] = (char) 0xc0;
751 ptr[1] = 0x00;
752 ptr[2] = 0x00;
753 ptr[3] = 0x00;
754 fix_new (frag,
755 ptr - frag->fr_literal,
756 4,
757 to_symbol,
758 (offsetT) 0,
759 0,
760 BFD_RELOC_SPU_PCREL16);
761}
762#endif
763
cd4a7468
AM
764/* Handle .brinfo <priority>,<lrlive>. */
765static void
766spu_brinfo (int ignore ATTRIBUTE_UNUSED)
767{
768 addressT priority;
769 addressT lrlive;
770
771 priority = get_absolute_expression ();
772 SKIP_WHITESPACE ();
773
774 lrlive = 0;
775 if (*input_line_pointer == ',')
776 {
777 ++input_line_pointer;
778 lrlive = get_absolute_expression ();
779 }
780
781 if (priority > 0x1fff)
782 {
783 as_bad (_("invalid priority '%lu'"), (unsigned long) priority);
784 priority = 0;
785 }
786
787 if (lrlive > 7)
788 {
789 as_bad (_("invalid lrlive '%lu'"), (unsigned long) lrlive);
790 lrlive = 0;
791 }
792
793 brinfo = (lrlive << 13) | priority;
794 demand_empty_rest_of_line ();
795}
796
ece5ef60
AM
797/* Support @ppu on symbols referenced in .int/.long/.word/.quad. */
798static void
799spu_cons (int nbytes)
800{
801 expressionS exp;
802
803 if (is_it_end_of_statement ())
804 {
805 demand_empty_rest_of_line ();
806 return;
807 }
808
809 do
810 {
e4c2619a
AM
811 char *save = input_line_pointer;
812
813 /* Use deferred_expression here so that an expression involving
814 a symbol that happens to be defined already as an spu symbol,
815 is not resolved. */
353ab861
AM
816 deferred_expression (&exp);
817 if ((exp.X_op == O_symbol
818 || exp.X_op == O_constant)
ece5ef60
AM
819 && strncasecmp (input_line_pointer, "@ppu", 4) == 0)
820 {
821 char *p = frag_more (nbytes);
822 enum bfd_reloc_code_real reloc;
823
824 /* Check for identifier@suffix+constant. */
825 input_line_pointer += 4;
826 if (*input_line_pointer == '-' || *input_line_pointer == '+')
827 {
828 expressionS new_exp;
829
e4c2619a 830 save = input_line_pointer;
ece5ef60
AM
831 expression (&new_exp);
832 if (new_exp.X_op == O_constant)
833 exp.X_add_number += new_exp.X_add_number;
e4c2619a
AM
834 else
835 input_line_pointer = save;
ece5ef60
AM
836 }
837
838 reloc = nbytes == 4 ? BFD_RELOC_SPU_PPU32 : BFD_RELOC_SPU_PPU64;
839 fix_new_exp (frag_now, p - frag_now->fr_literal, nbytes,
840 &exp, 0, reloc);
841 }
842 else
e4c2619a
AM
843 {
844 /* Don't use deferred_expression for anything else.
845 deferred_expression won't evaulate dot at the point it is
846 used. */
847 input_line_pointer = save;
848 expression (&exp);
849 emit_expr (&exp, nbytes);
850 }
ece5ef60
AM
851 }
852 while (*input_line_pointer++ == ',');
853
854 /* Put terminator back into stream. */
855 input_line_pointer--;
856 demand_empty_rest_of_line ();
857}
858
e9f53129
AM
859int
860md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
861 segT segment_type ATTRIBUTE_UNUSED)
862{
863 as_fatal (_("Relaxation should never occur"));
864 return -1;
865}
866
867/* If while processing a fixup, a reloc really needs to be created,
868 then it is done here. */
869
870arelent *
871tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
872{
873 arelent *reloc;
add39d23
TS
874 reloc = XNEW (arelent);
875 reloc->sym_ptr_ptr = XNEW (asymbol *);
e9f53129
AM
876 if (fixp->fx_addsy)
877 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
878 else if (fixp->fx_subsy)
879 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
353ab861
AM
880 else
881 abort ();
e9f53129
AM
882 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
883 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
884 if (reloc->howto == (reloc_howto_type *) NULL)
885 {
886 as_bad_where (fixp->fx_file, fixp->fx_line,
887 _("reloc %d not supported by object file format"),
888 (int) fixp->fx_r_type);
889 return NULL;
890 }
891 reloc->addend = fixp->fx_addnumber;
892 return reloc;
893}
894
895/* Round up a section's size to the appropriate boundary. */
896
897valueT
898md_section_align (segT seg, valueT size)
899{
fd361982 900 int align = bfd_section_alignment (seg);
e9f53129
AM
901 valueT mask = ((valueT) 1 << align) - 1;
902
903 return (size + mask) & ~mask;
904}
905
906/* Where a PC relative offset is calculated from. On the spu they
907 are calculated from the beginning of the branch instruction. */
908
909long
910md_pcrel_from (fixS *fixp)
911{
912 return fixp->fx_frag->fr_address + fixp->fx_where;
913}
914
915/* Fill in rs_align_code fragments. */
916
917void
918spu_handle_align (fragS *fragp)
919{
920 static const unsigned char nop_pattern[8] = {
921 0x40, 0x20, 0x00, 0x00, /* even nop */
922 0x00, 0x20, 0x00, 0x00, /* odd nop */
923 };
924
925 int bytes;
926 char *p;
927
928 if (fragp->fr_type != rs_align_code)
929 return;
930
931 bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
932 p = fragp->fr_literal + fragp->fr_fix;
933
934 if (bytes & 3)
935 {
936 int fix = bytes & 3;
937 memset (p, 0, fix);
938 p += fix;
939 bytes -= fix;
940 fragp->fr_fix += fix;
941 }
942 if (bytes & 4)
943 {
944 memcpy (p, &nop_pattern[4], 4);
945 p += 4;
946 bytes -= 4;
947 fragp->fr_fix += 4;
948 }
949
950 memcpy (p, nop_pattern, 8);
951 fragp->fr_var = 8;
952}
953
954void
955md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
956{
957 unsigned int res;
cd4a7468 958 unsigned int mask;
e9f53129
AM
959 valueT val = *valP;
960 char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
961
962 if (fixP->fx_subsy != (symbolS *) NULL)
963 {
964 /* We can't actually support subtracting a symbol. */
965 as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
966 }
967
968 if (fixP->fx_addsy != NULL)
969 {
970 if (fixP->fx_pcrel)
971 {
972 /* Hack around bfd_install_relocation brain damage. */
973 val += fixP->fx_frag->fr_address + fixP->fx_where;
974
975 switch (fixP->fx_r_type)
976 {
977 case BFD_RELOC_32:
978 fixP->fx_r_type = BFD_RELOC_32_PCREL;
979 break;
980
981 case BFD_RELOC_SPU_PCREL16:
982 case BFD_RELOC_SPU_PCREL9a:
983 case BFD_RELOC_SPU_PCREL9b:
984 case BFD_RELOC_32_PCREL:
985 break;
986
987 default:
988 as_bad_where (fixP->fx_file, fixP->fx_line,
989 _("expression too complex"));
990 break;
991 }
992 }
993 }
994
995 fixP->fx_addnumber = val;
996
353ab861 997 if (fixP->fx_r_type == BFD_RELOC_SPU_PPU32
8fdcc58d
TS
998 || fixP->fx_r_type == BFD_RELOC_SPU_PPU64
999 || fixP->fx_r_type == BFD_RELOC_SPU_ADD_PIC)
353ab861
AM
1000 return;
1001
e9f53129
AM
1002 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
1003 {
1004 fixP->fx_done = 1;
1005 res = 0;
cd4a7468 1006 mask = 0;
840edabd 1007 if (fixP->tc_fix_data.arg_format > A_P)
e9f53129 1008 {
840edabd
AM
1009 int hi = arg_encode[fixP->tc_fix_data.arg_format].hi;
1010 int lo = arg_encode[fixP->tc_fix_data.arg_format].lo;
e9f53129
AM
1011 if (hi > lo && ((offsetT) val < lo || (offsetT) val > hi))
1012 as_bad_where (fixP->fx_file, fixP->fx_line,
20203fb9 1013 _("Relocation doesn't fit. (relocation value = 0x%lx)"),
e9f53129
AM
1014 (long) val);
1015 }
1016
1017 switch (fixP->fx_r_type)
cd4a7468
AM
1018 {
1019 case BFD_RELOC_8:
e9f53129
AM
1020 md_number_to_chars (place, val, 1);
1021 return;
1022
cd4a7468 1023 case BFD_RELOC_16:
e9f53129
AM
1024 md_number_to_chars (place, val, 2);
1025 return;
1026
cd4a7468 1027 case BFD_RELOC_32:
d62f07d0 1028 case BFD_RELOC_32_PCREL:
e9f53129
AM
1029 md_number_to_chars (place, val, 4);
1030 return;
1031
cd4a7468 1032 case BFD_RELOC_64:
e9f53129
AM
1033 md_number_to_chars (place, val, 8);
1034 return;
1035
cd4a7468
AM
1036 case BFD_RELOC_SPU_IMM7:
1037 res = val << 14;
1038 mask = 0x7f << 14;
1039 break;
e9f53129 1040
cd4a7468
AM
1041 case BFD_RELOC_SPU_IMM8:
1042 res = val << 14;
1043 mask = 0xff << 14;
1044 break;
e9f53129 1045
cd4a7468
AM
1046 case BFD_RELOC_SPU_IMM10:
1047 res = val << 14;
1048 mask = 0x3ff << 14;
1049 break;
e9f53129 1050
cd4a7468
AM
1051 case BFD_RELOC_SPU_IMM10W:
1052 res = val << 10;
1053 mask = 0x3ff0 << 10;
1054 break;
e9f53129 1055
cd4a7468
AM
1056 case BFD_RELOC_SPU_IMM16:
1057 res = val << 7;
1058 mask = 0xffff << 7;
1059 break;
e9f53129 1060
cd4a7468
AM
1061 case BFD_RELOC_SPU_IMM16W:
1062 res = val << 5;
1063 mask = 0x3fffc << 5;
1064 break;
e9f53129 1065
cd4a7468
AM
1066 case BFD_RELOC_SPU_IMM18:
1067 res = val << 7;
1068 mask = 0x3ffff << 7;
1069 break;
e9f53129 1070
cd4a7468
AM
1071 case BFD_RELOC_SPU_PCREL9a:
1072 res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14);
1073 mask = (0x1fc >> 2) | (0x600 << 14);
1074 break;
e9f53129 1075
cd4a7468
AM
1076 case BFD_RELOC_SPU_PCREL9b:
1077 res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5);
1078 mask = (0x1fc >> 2) | (0x600 << 5);
1079 break;
e9f53129 1080
cd4a7468
AM
1081 case BFD_RELOC_SPU_PCREL16:
1082 res = val << 5;
1083 mask = 0x3fffc << 5;
1084 break;
e9f53129 1085
d62f07d0 1086 case BFD_RELOC_SPU_HI16:
cd4a7468
AM
1087 res = val >> 9;
1088 mask = 0xffff << 7;
d62f07d0
AM
1089 break;
1090
1091 case BFD_RELOC_SPU_LO16:
cd4a7468
AM
1092 res = val << 7;
1093 mask = 0xffff << 7;
d62f07d0
AM
1094 break;
1095
cd4a7468
AM
1096 default:
1097 as_bad_where (fixP->fx_file, fixP->fx_line,
1098 _("reloc %d not supported by object file format"),
1099 (int) fixP->fx_r_type);
1100 }
1101
1102 res &= mask;
1103 place[0] = (place[0] & (~mask >> 24)) | ((res >> 24) & 0xff);
1104 place[1] = (place[1] & (~mask >> 16)) | ((res >> 16) & 0xff);
1105 place[2] = (place[2] & (~mask >> 8)) | ((res >> 8) & 0xff);
1106 place[3] = (place[3] & ~mask) | (res & 0xff);
e9f53129
AM
1107 }
1108}
This page took 0.740158 seconds and 4 git commands to generate.