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