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