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