Remove trailing spaces in gas
[deliverable/binutils-gdb.git] / gas / config / tc-spu.c
CommitLineData
e9f53129
AM
1/* spu.c -- Assembler for the IBM Synergistic Processing Unit (SPU)
2
b90efa5b 3 Copyright (C) 2006-2015 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) \
29 { MACFORMAT, (OPCODE) << (32-11), MNEMONIC, ASMFORMAT },
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
159md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
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];
248 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
e9f53129
AM
719char *
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 {
353ab861
AM
818 deferred_expression (&exp);
819 if ((exp.X_op == O_symbol
820 || exp.X_op == O_constant)
ece5ef60
AM
821 && strncasecmp (input_line_pointer, "@ppu", 4) == 0)
822 {
823 char *p = frag_more (nbytes);
824 enum bfd_reloc_code_real reloc;
825
826 /* Check for identifier@suffix+constant. */
827 input_line_pointer += 4;
828 if (*input_line_pointer == '-' || *input_line_pointer == '+')
829 {
830 expressionS new_exp;
831
832 expression (&new_exp);
833 if (new_exp.X_op == O_constant)
834 exp.X_add_number += new_exp.X_add_number;
835 }
836
837 reloc = nbytes == 4 ? BFD_RELOC_SPU_PPU32 : BFD_RELOC_SPU_PPU64;
838 fix_new_exp (frag_now, p - frag_now->fr_literal, nbytes,
839 &exp, 0, reloc);
840 }
841 else
842 emit_expr (&exp, nbytes);
843 }
844 while (*input_line_pointer++ == ',');
845
846 /* Put terminator back into stream. */
847 input_line_pointer--;
848 demand_empty_rest_of_line ();
849}
850
e9f53129
AM
851int
852md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
853 segT segment_type ATTRIBUTE_UNUSED)
854{
855 as_fatal (_("Relaxation should never occur"));
856 return -1;
857}
858
859/* If while processing a fixup, a reloc really needs to be created,
860 then it is done here. */
861
862arelent *
863tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
864{
865 arelent *reloc;
866 reloc = (arelent *) xmalloc (sizeof (arelent));
867 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
868 if (fixp->fx_addsy)
869 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
870 else if (fixp->fx_subsy)
871 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
353ab861
AM
872 else
873 abort ();
e9f53129
AM
874 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
875 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
876 if (reloc->howto == (reloc_howto_type *) NULL)
877 {
878 as_bad_where (fixp->fx_file, fixp->fx_line,
879 _("reloc %d not supported by object file format"),
880 (int) fixp->fx_r_type);
881 return NULL;
882 }
883 reloc->addend = fixp->fx_addnumber;
884 return reloc;
885}
886
887/* Round up a section's size to the appropriate boundary. */
888
889valueT
890md_section_align (segT seg, valueT size)
891{
892 int align = bfd_get_section_alignment (stdoutput, seg);
893 valueT mask = ((valueT) 1 << align) - 1;
894
895 return (size + mask) & ~mask;
896}
897
898/* Where a PC relative offset is calculated from. On the spu they
899 are calculated from the beginning of the branch instruction. */
900
901long
902md_pcrel_from (fixS *fixp)
903{
904 return fixp->fx_frag->fr_address + fixp->fx_where;
905}
906
907/* Fill in rs_align_code fragments. */
908
909void
910spu_handle_align (fragS *fragp)
911{
912 static const unsigned char nop_pattern[8] = {
913 0x40, 0x20, 0x00, 0x00, /* even nop */
914 0x00, 0x20, 0x00, 0x00, /* odd nop */
915 };
916
917 int bytes;
918 char *p;
919
920 if (fragp->fr_type != rs_align_code)
921 return;
922
923 bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
924 p = fragp->fr_literal + fragp->fr_fix;
925
926 if (bytes & 3)
927 {
928 int fix = bytes & 3;
929 memset (p, 0, fix);
930 p += fix;
931 bytes -= fix;
932 fragp->fr_fix += fix;
933 }
934 if (bytes & 4)
935 {
936 memcpy (p, &nop_pattern[4], 4);
937 p += 4;
938 bytes -= 4;
939 fragp->fr_fix += 4;
940 }
941
942 memcpy (p, nop_pattern, 8);
943 fragp->fr_var = 8;
944}
945
946void
947md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
948{
949 unsigned int res;
cd4a7468 950 unsigned int mask;
e9f53129
AM
951 valueT val = *valP;
952 char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
953
954 if (fixP->fx_subsy != (symbolS *) NULL)
955 {
956 /* We can't actually support subtracting a symbol. */
957 as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
958 }
959
960 if (fixP->fx_addsy != NULL)
961 {
962 if (fixP->fx_pcrel)
963 {
964 /* Hack around bfd_install_relocation brain damage. */
965 val += fixP->fx_frag->fr_address + fixP->fx_where;
966
967 switch (fixP->fx_r_type)
968 {
969 case BFD_RELOC_32:
970 fixP->fx_r_type = BFD_RELOC_32_PCREL;
971 break;
972
973 case BFD_RELOC_SPU_PCREL16:
974 case BFD_RELOC_SPU_PCREL9a:
975 case BFD_RELOC_SPU_PCREL9b:
976 case BFD_RELOC_32_PCREL:
977 break;
978
979 default:
980 as_bad_where (fixP->fx_file, fixP->fx_line,
981 _("expression too complex"));
982 break;
983 }
984 }
985 }
986
987 fixP->fx_addnumber = val;
988
353ab861 989 if (fixP->fx_r_type == BFD_RELOC_SPU_PPU32
8fdcc58d
TS
990 || fixP->fx_r_type == BFD_RELOC_SPU_PPU64
991 || fixP->fx_r_type == BFD_RELOC_SPU_ADD_PIC)
353ab861
AM
992 return;
993
e9f53129
AM
994 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
995 {
996 fixP->fx_done = 1;
997 res = 0;
cd4a7468 998 mask = 0;
840edabd 999 if (fixP->tc_fix_data.arg_format > A_P)
e9f53129 1000 {
840edabd
AM
1001 int hi = arg_encode[fixP->tc_fix_data.arg_format].hi;
1002 int lo = arg_encode[fixP->tc_fix_data.arg_format].lo;
e9f53129
AM
1003 if (hi > lo && ((offsetT) val < lo || (offsetT) val > hi))
1004 as_bad_where (fixP->fx_file, fixP->fx_line,
20203fb9 1005 _("Relocation doesn't fit. (relocation value = 0x%lx)"),
e9f53129
AM
1006 (long) val);
1007 }
1008
1009 switch (fixP->fx_r_type)
cd4a7468
AM
1010 {
1011 case BFD_RELOC_8:
e9f53129
AM
1012 md_number_to_chars (place, val, 1);
1013 return;
1014
cd4a7468 1015 case BFD_RELOC_16:
e9f53129
AM
1016 md_number_to_chars (place, val, 2);
1017 return;
1018
cd4a7468 1019 case BFD_RELOC_32:
d62f07d0 1020 case BFD_RELOC_32_PCREL:
e9f53129
AM
1021 md_number_to_chars (place, val, 4);
1022 return;
1023
cd4a7468 1024 case BFD_RELOC_64:
e9f53129
AM
1025 md_number_to_chars (place, val, 8);
1026 return;
1027
cd4a7468
AM
1028 case BFD_RELOC_SPU_IMM7:
1029 res = val << 14;
1030 mask = 0x7f << 14;
1031 break;
e9f53129 1032
cd4a7468
AM
1033 case BFD_RELOC_SPU_IMM8:
1034 res = val << 14;
1035 mask = 0xff << 14;
1036 break;
e9f53129 1037
cd4a7468
AM
1038 case BFD_RELOC_SPU_IMM10:
1039 res = val << 14;
1040 mask = 0x3ff << 14;
1041 break;
e9f53129 1042
cd4a7468
AM
1043 case BFD_RELOC_SPU_IMM10W:
1044 res = val << 10;
1045 mask = 0x3ff0 << 10;
1046 break;
e9f53129 1047
cd4a7468
AM
1048 case BFD_RELOC_SPU_IMM16:
1049 res = val << 7;
1050 mask = 0xffff << 7;
1051 break;
e9f53129 1052
cd4a7468
AM
1053 case BFD_RELOC_SPU_IMM16W:
1054 res = val << 5;
1055 mask = 0x3fffc << 5;
1056 break;
e9f53129 1057
cd4a7468
AM
1058 case BFD_RELOC_SPU_IMM18:
1059 res = val << 7;
1060 mask = 0x3ffff << 7;
1061 break;
e9f53129 1062
cd4a7468
AM
1063 case BFD_RELOC_SPU_PCREL9a:
1064 res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14);
1065 mask = (0x1fc >> 2) | (0x600 << 14);
1066 break;
e9f53129 1067
cd4a7468
AM
1068 case BFD_RELOC_SPU_PCREL9b:
1069 res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5);
1070 mask = (0x1fc >> 2) | (0x600 << 5);
1071 break;
e9f53129 1072
cd4a7468
AM
1073 case BFD_RELOC_SPU_PCREL16:
1074 res = val << 5;
1075 mask = 0x3fffc << 5;
1076 break;
e9f53129 1077
d62f07d0 1078 case BFD_RELOC_SPU_HI16:
cd4a7468
AM
1079 res = val >> 9;
1080 mask = 0xffff << 7;
d62f07d0
AM
1081 break;
1082
1083 case BFD_RELOC_SPU_LO16:
cd4a7468
AM
1084 res = val << 7;
1085 mask = 0xffff << 7;
d62f07d0
AM
1086 break;
1087
cd4a7468
AM
1088 default:
1089 as_bad_where (fixP->fx_file, fixP->fx_line,
1090 _("reloc %d not supported by object file format"),
1091 (int) fixP->fx_r_type);
1092 }
1093
1094 res &= mask;
1095 place[0] = (place[0] & (~mask >> 24)) | ((res >> 24) & 0xff);
1096 place[1] = (place[1] & (~mask >> 16)) | ((res >> 16) & 0xff);
1097 place[2] = (place[2] & (~mask >> 8)) | ((res >> 8) & 0xff);
1098 place[3] = (place[3] & ~mask) | (res & 0xff);
e9f53129
AM
1099 }
1100}
This page took 0.618142 seconds and 4 git commands to generate.