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
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];
47 int flag[MAX_RELOCS];
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},
e9f53129 94 {"string", stringer, 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;
306 insn.flag[i] = 0;
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;
355 bfd_reloc_code_real_type reloc = arg_encode[insn.reloc_arg[i]].reloc;
356 int pcrel = 0;
ece5ef60 357
e9f53129
AM
358 if (reloc == BFD_RELOC_SPU_PCREL9a
359 || reloc == BFD_RELOC_SPU_PCREL9b
360 || reloc == BFD_RELOC_SPU_PCREL16)
361 pcrel = 1;
ece5ef60 362 if (insn.flag[i] == 1)
e9f53129 363 reloc = BFD_RELOC_SPU_HI16;
ece5ef60 364 else if (insn.flag[i] == 2)
e9f53129
AM
365 reloc = BFD_RELOC_SPU_LO16;
366 fixP = fix_new_exp (frag_now,
367 thisfrag - frag_now->fr_literal,
368 4,
369 &insn.exp[i],
370 pcrel,
371 reloc);
840edabd
AM
372 fixP->tc_fix_data.arg_format = insn.reloc_arg[i];
373 fixP->tc_fix_data.insn_tag = insn.tag;
e9f53129
AM
374 }
375 dwarf2_emit_insn (4);
376}
377
378static int
379calcop (struct spu_opcode *format, const char *param, struct spu_insn *insn)
380{
381 int i;
382 int paren = 0;
383 int arg;
384
385 for (i = 1; i <= format->arg[0]; i++)
386 {
387 arg = format->arg[i];
388 syntax_error_arg = i;
389
390 while (ISSPACE (*param))
391 param++;
392 if (*param == 0 || *param == ',')
393 return 0;
394 if (arg < A_P)
395 param = get_reg (param, insn, arg, 1);
396 else if (arg > A_P)
397 param = get_imm (param, insn, arg);
398 else if (arg == A_P)
399 {
400 paren++;
401 if ('(' != *param++)
402 return 0;
403 }
404
405 if (!param)
406 return 0;
407
408 while (ISSPACE (*param))
409 param++;
410
411 if (arg != A_P && paren)
412 {
413 paren--;
414 if (')' != *param++)
415 return 0;
416 }
417 else if (i < format->arg[0]
418 && format->arg[i] != A_P
419 && format->arg[i+1] != A_P)
420 {
421 if (',' != *param++)
422 {
423 syntax_error_arg++;
424 return 0;
425 }
426 }
427 }
428 while (ISSPACE (*param))
429 param++;
430 return !paren && (*param == 0 || *param == '\n');
431}
432
433struct reg_name {
434 unsigned int regno;
435 unsigned int length;
436 char name[32];
437};
438
439#define REG_NAME(NO,NM) { NO, sizeof (NM) - 1, NM }
440
441static struct reg_name reg_name[] = {
442 REG_NAME (0, "lr"), /* link register */
443 REG_NAME (1, "sp"), /* stack pointer */
444 REG_NAME (0, "rp"), /* link register */
445 REG_NAME (127, "fp"), /* frame pointer */
446};
447
448static struct reg_name sp_reg_name[] = {
449};
450
451static struct reg_name ch_reg_name[] = {
452 REG_NAME ( 0, "SPU_RdEventStat"),
453 REG_NAME ( 1, "SPU_WrEventMask"),
454 REG_NAME ( 2, "SPU_WrEventAck"),
455 REG_NAME ( 3, "SPU_RdSigNotify1"),
456 REG_NAME ( 4, "SPU_RdSigNotify2"),
457 REG_NAME ( 7, "SPU_WrDec"),
458 REG_NAME ( 8, "SPU_RdDec"),
459 REG_NAME ( 11, "SPU_RdEventMask"), /* DD2.0 only */
460 REG_NAME ( 13, "SPU_RdMachStat"),
461 REG_NAME ( 14, "SPU_WrSRR0"),
462 REG_NAME ( 15, "SPU_RdSRR0"),
463 REG_NAME ( 28, "SPU_WrOutMbox"),
464 REG_NAME ( 29, "SPU_RdInMbox"),
465 REG_NAME ( 30, "SPU_WrOutIntrMbox"),
466 REG_NAME ( 9, "MFC_WrMSSyncReq"),
467 REG_NAME ( 12, "MFC_RdTagMask"), /* DD2.0 only */
468 REG_NAME ( 16, "MFC_LSA"),
469 REG_NAME ( 17, "MFC_EAH"),
470 REG_NAME ( 18, "MFC_EAL"),
471 REG_NAME ( 19, "MFC_Size"),
472 REG_NAME ( 20, "MFC_TagID"),
473 REG_NAME ( 21, "MFC_Cmd"),
474 REG_NAME ( 22, "MFC_WrTagMask"),
475 REG_NAME ( 23, "MFC_WrTagUpdate"),
476 REG_NAME ( 24, "MFC_RdTagStat"),
477 REG_NAME ( 25, "MFC_RdListStallStat"),
478 REG_NAME ( 26, "MFC_WrListStallAck"),
479 REG_NAME ( 27, "MFC_RdAtomicStat"),
480};
481#undef REG_NAME
482
483static const char *
484get_reg (const char *param, struct spu_insn *insn, int arg, int accept_expr)
485{
486 unsigned regno;
487 int saw_prefix = 0;
488
489 if (*param == '$')
490 {
491 saw_prefix = 1;
492 param++;
493 }
494
495 if (arg == A_H) /* Channel */
496 {
497 if ((param[0] == 'c' || param[0] == 'C')
498 && (param[1] == 'h' || param[1] == 'H')
499 && ISDIGIT (param[2]))
500 param += 2;
501 }
502 else if (arg == A_S) /* Special purpose register */
503 {
504 if ((param[0] == 's' || param[0] == 'S')
505 && (param[1] == 'p' || param[1] == 'P')
506 && ISDIGIT (param[2]))
507 param += 2;
508 }
509
510 if (ISDIGIT (*param))
511 {
512 regno = 0;
513 while (ISDIGIT (*param))
514 regno = regno * 10 + *param++ - '0';
515 }
516 else
517 {
518 struct reg_name *rn;
519 unsigned int i, n, l = 0;
520
521 if (arg == A_H) /* Channel */
522 {
523 rn = ch_reg_name;
524 n = sizeof (ch_reg_name) / sizeof (*ch_reg_name);
525 }
526 else if (arg == A_S) /* Special purpose register */
527 {
528 rn = sp_reg_name;
529 n = sizeof (sp_reg_name) / sizeof (*sp_reg_name);
530 }
531 else
532 {
533 rn = reg_name;
534 n = sizeof (reg_name) / sizeof (*reg_name);
535 }
536 regno = 128;
537 for (i = 0; i < n; i++)
538 if (rn[i].length > l
539 && 0 == strncasecmp (param, rn[i].name, rn[i].length))
540 {
541 l = rn[i].length;
542 regno = rn[i].regno;
543 }
544 param += l;
545 }
546
547 if (!use_dd2
548 && arg == A_H)
549 {
550 if (regno == 11)
551 as_bad (_("'SPU_RdEventMask' (channel 11) is only available in DD2.0 or higher."));
552 else if (regno == 12)
553 as_bad (_("'MFC_RdTagMask' (channel 12) is only available in DD2.0 or higher."));
554 }
555
556 if (regno < 128)
557 {
558 insn->opcode |= regno << arg_encode[arg].pos;
559 if ((!saw_prefix && syntax_reg == 1)
560 || (saw_prefix && syntax_reg == 2))
561 syntax_reg |= 4;
562 syntax_reg |= saw_prefix ? 1 : 2;
563 return param;
564 }
565
566 if (accept_expr)
567 {
568 char *save_ptr;
569 expressionS ex;
570 save_ptr = input_line_pointer;
571 input_line_pointer = (char *)param;
572 expression (&ex);
573 param = input_line_pointer;
574 input_line_pointer = save_ptr;
575 if (ex.X_op == O_register || ex.X_op == O_constant)
576 {
577 insn->opcode |= ex.X_add_number << arg_encode[arg].pos;
578 return param;
579 }
580 }
581 return 0;
582}
583
584static const char *
585get_imm (const char *param, struct spu_insn *insn, int arg)
586{
587 int val;
588 char *save_ptr;
589 int low = 0, high = 0;
590 int reloc_i = insn->reloc_arg[0] >= 0 ? 1 : 0;
591
ece5ef60 592 if (strncasecmp (param, "%lo(", 4) == 0)
e9f53129
AM
593 {
594 param += 3;
595 low = 1;
596 as_warn (_("Using old style, %%lo(expr), please change to PPC style, expr@l."));
597 }
ece5ef60 598 else if (strncasecmp (param, "%hi(", 4) == 0)
e9f53129
AM
599 {
600 param += 3;
601 high = 1;
602 as_warn (_("Using old style, %%hi(expr), please change to PPC style, expr@h."));
603 }
ece5ef60 604 else if (strncasecmp (param, "%pic(", 5) == 0)
e9f53129
AM
605 {
606 /* Currently we expect %pic(expr) == expr, so do nothing here.
ece5ef60 607 i.e. for code loaded at address 0 $toc will be 0. */
e9f53129
AM
608 param += 4;
609 }
610
611 if (*param == '$')
612 {
613 /* Symbols can start with $, but if this symbol matches a register
ece5ef60
AM
614 name, it's probably a mistake. The only way to avoid this
615 warning is to rename the symbol. */
e9f53129
AM
616 struct spu_insn tmp_insn;
617 const char *np = get_reg (param, &tmp_insn, arg, 0);
618
619 if (np)
620 syntax_error_param = np;
621 }
622
623 save_ptr = input_line_pointer;
624 input_line_pointer = (char *) param;
625 expression (&insn->exp[reloc_i]);
626 param = input_line_pointer;
627 input_line_pointer = save_ptr;
628
629 /* Similar to ppc_elf_suffix in tc-ppc.c. We have so few cases to
ece5ef60 630 handle we do it inlined here. */
e9f53129
AM
631 if (param[0] == '@' && !ISALNUM (param[2]) && param[2] != '@')
632 {
633 if (param[1] == 'h' || param[1] == 'H')
634 {
635 high = 1;
636 param += 2;
637 }
638 else if (param[1] == 'l' || param[1] == 'L')
639 {
640 low = 1;
641 param += 2;
642 }
643 }
644
e9f53129
AM
645 if (insn->exp[reloc_i].X_op == O_constant)
646 {
ece5ef60
AM
647 val = insn->exp[reloc_i].X_add_number;
648
e9f53129
AM
649 if (emulate_apuasm)
650 {
651 /* Convert the value to a format we expect. */
652 val <<= arg_encode[arg].rshift;
653 if (arg == A_U7A)
654 val = 173 - val;
655 else if (arg == A_U7B)
656 val = 155 - val;
657 }
658
659 if (high)
660 val = val >> 16;
661 else if (low)
662 val = val & 0xffff;
663
664 /* Warn about out of range expressions. */
665 {
666 int hi = arg_encode[arg].hi;
667 int lo = arg_encode[arg].lo;
668 int whi = arg_encode[arg].whi;
669 int wlo = arg_encode[arg].wlo;
670
671 if (hi > lo && (val < lo || val > hi))
672 as_fatal (_("Constant expression %d out of range, [%d, %d]."),
673 val, lo, hi);
674 else if (whi > wlo && (val < wlo || val > whi))
675 as_warn (_("Constant expression %d out of range, [%d, %d]."),
676 val, wlo, whi);
677 }
678
679 if (arg == A_U7A)
680 val = 173 - val;
681 else if (arg == A_U7B)
682 val = 155 - val;
683
684 /* Branch hints have a split encoding. Do the bottom part. */
685 if (arg == A_S11 || arg == A_S11I)
686 insn->opcode |= ((val >> 2) & 0x7f);
687
688 insn->opcode |= (((val >> arg_encode[arg].rshift)
689 & ((1 << arg_encode[arg].size) - 1))
690 << arg_encode[arg].pos);
691 insn->reloc_arg[reloc_i] = -1;
692 insn->flag[reloc_i] = 0;
693 }
694 else
695 {
696 insn->reloc_arg[reloc_i] = arg;
697 if (high)
ece5ef60
AM
698 insn->flag[reloc_i] = 1;
699 else if (low)
700 insn->flag[reloc_i] = 2;
e9f53129
AM
701 }
702
703 return param;
704}
705
706#define MAX_LITTLENUMS 6
707
708/* Turn a string in input_line_pointer into a floating point constant of type
709 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
710 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
711 */
712char *
713md_atof (int type, char *litP, int *sizeP)
714{
715 int prec;
716 LITTLENUM_TYPE words[MAX_LITTLENUMS];
717 LITTLENUM_TYPE *wordP;
718 char *t;
719
720 switch (type)
721 {
722 case 'f':
723 case 'F':
724 case 's':
725 case 'S':
726 prec = 2;
727 break;
728
729 case 'd':
730 case 'D':
731 case 'r':
732 case 'R':
733 prec = 4;
734 break;
735
736 case 'x':
737 case 'X':
738 prec = 6;
739 break;
740
741 case 'p':
742 case 'P':
743 prec = 6;
744 break;
745
746 default:
747 *sizeP = 0;
748 return _("Bad call to MD_ATOF()");
749 }
750 t = atof_ieee (input_line_pointer, type, words);
751 if (t)
752 input_line_pointer = t;
753
754 *sizeP = prec * sizeof (LITTLENUM_TYPE);
755 for (wordP = words; prec--;)
756 {
757 md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
758 litP += sizeof (LITTLENUM_TYPE);
759 }
760 return 0;
761}
762
763#ifndef WORKING_DOT_WORD
764int md_short_jump_size = 4;
765
766void
767md_create_short_jump (char *ptr,
768 addressT from_addr ATTRIBUTE_UNUSED,
769 addressT to_addr ATTRIBUTE_UNUSED,
770 fragS *frag,
771 symbolS *to_symbol)
772{
773 ptr[0] = (char) 0xc0;
774 ptr[1] = 0x00;
775 ptr[2] = 0x00;
776 ptr[3] = 0x00;
777 fix_new (frag,
778 ptr - frag->fr_literal,
779 4,
780 to_symbol,
781 (offsetT) 0,
782 0,
783 BFD_RELOC_SPU_PCREL16);
784}
785
786int md_long_jump_size = 4;
787
788void
789md_create_long_jump (char *ptr,
790 addressT from_addr ATTRIBUTE_UNUSED,
791 addressT to_addr ATTRIBUTE_UNUSED,
792 fragS *frag,
793 symbolS *to_symbol)
794{
795 ptr[0] = (char) 0xc0;
796 ptr[1] = 0x00;
797 ptr[2] = 0x00;
798 ptr[3] = 0x00;
799 fix_new (frag,
800 ptr - frag->fr_literal,
801 4,
802 to_symbol,
803 (offsetT) 0,
804 0,
805 BFD_RELOC_SPU_PCREL16);
806}
807#endif
808
ece5ef60
AM
809/* Support @ppu on symbols referenced in .int/.long/.word/.quad. */
810static void
811spu_cons (int nbytes)
812{
813 expressionS exp;
814
815 if (is_it_end_of_statement ())
816 {
817 demand_empty_rest_of_line ();
818 return;
819 }
820
821 do
822 {
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
837 expression (&new_exp);
838 if (new_exp.X_op == O_constant)
839 exp.X_add_number += new_exp.X_add_number;
840 }
841
842 reloc = nbytes == 4 ? BFD_RELOC_SPU_PPU32 : BFD_RELOC_SPU_PPU64;
843 fix_new_exp (frag_now, p - frag_now->fr_literal, nbytes,
844 &exp, 0, reloc);
845 }
846 else
847 emit_expr (&exp, nbytes);
848 }
849 while (*input_line_pointer++ == ',');
850
851 /* Put terminator back into stream. */
852 input_line_pointer--;
853 demand_empty_rest_of_line ();
854}
855
e9f53129
AM
856int
857md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
858 segT segment_type ATTRIBUTE_UNUSED)
859{
860 as_fatal (_("Relaxation should never occur"));
861 return -1;
862}
863
864/* If while processing a fixup, a reloc really needs to be created,
865 then it is done here. */
866
867arelent *
868tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
869{
870 arelent *reloc;
871 reloc = (arelent *) xmalloc (sizeof (arelent));
872 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
873 if (fixp->fx_addsy)
874 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
875 else if (fixp->fx_subsy)
876 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
353ab861
AM
877 else
878 abort ();
e9f53129
AM
879 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
880 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
881 if (reloc->howto == (reloc_howto_type *) NULL)
882 {
883 as_bad_where (fixp->fx_file, fixp->fx_line,
884 _("reloc %d not supported by object file format"),
885 (int) fixp->fx_r_type);
886 return NULL;
887 }
888 reloc->addend = fixp->fx_addnumber;
889 return reloc;
890}
891
892/* Round up a section's size to the appropriate boundary. */
893
894valueT
895md_section_align (segT seg, valueT size)
896{
897 int align = bfd_get_section_alignment (stdoutput, seg);
898 valueT mask = ((valueT) 1 << align) - 1;
899
900 return (size + mask) & ~mask;
901}
902
903/* Where a PC relative offset is calculated from. On the spu they
904 are calculated from the beginning of the branch instruction. */
905
906long
907md_pcrel_from (fixS *fixp)
908{
909 return fixp->fx_frag->fr_address + fixp->fx_where;
910}
911
912/* Fill in rs_align_code fragments. */
913
914void
915spu_handle_align (fragS *fragp)
916{
917 static const unsigned char nop_pattern[8] = {
918 0x40, 0x20, 0x00, 0x00, /* even nop */
919 0x00, 0x20, 0x00, 0x00, /* odd nop */
920 };
921
922 int bytes;
923 char *p;
924
925 if (fragp->fr_type != rs_align_code)
926 return;
927
928 bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
929 p = fragp->fr_literal + fragp->fr_fix;
930
931 if (bytes & 3)
932 {
933 int fix = bytes & 3;
934 memset (p, 0, fix);
935 p += fix;
936 bytes -= fix;
937 fragp->fr_fix += fix;
938 }
939 if (bytes & 4)
940 {
941 memcpy (p, &nop_pattern[4], 4);
942 p += 4;
943 bytes -= 4;
944 fragp->fr_fix += 4;
945 }
946
947 memcpy (p, nop_pattern, 8);
948 fragp->fr_var = 8;
949}
950
951void
952md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
953{
954 unsigned int res;
955 valueT val = *valP;
956 char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
957
958 if (fixP->fx_subsy != (symbolS *) NULL)
959 {
960 /* We can't actually support subtracting a symbol. */
961 as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
962 }
963
964 if (fixP->fx_addsy != NULL)
965 {
966 if (fixP->fx_pcrel)
967 {
968 /* Hack around bfd_install_relocation brain damage. */
969 val += fixP->fx_frag->fr_address + fixP->fx_where;
970
971 switch (fixP->fx_r_type)
972 {
973 case BFD_RELOC_32:
974 fixP->fx_r_type = BFD_RELOC_32_PCREL;
975 break;
976
977 case BFD_RELOC_SPU_PCREL16:
978 case BFD_RELOC_SPU_PCREL9a:
979 case BFD_RELOC_SPU_PCREL9b:
980 case BFD_RELOC_32_PCREL:
981 break;
982
983 default:
984 as_bad_where (fixP->fx_file, fixP->fx_line,
985 _("expression too complex"));
986 break;
987 }
988 }
989 }
990
991 fixP->fx_addnumber = val;
992
353ab861
AM
993 if (fixP->fx_r_type == BFD_RELOC_SPU_PPU32
994 || fixP->fx_r_type == BFD_RELOC_SPU_PPU64)
995 return;
996
e9f53129
AM
997 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
998 {
999 fixP->fx_done = 1;
1000 res = 0;
840edabd 1001 if (fixP->tc_fix_data.arg_format > A_P)
e9f53129 1002 {
840edabd
AM
1003 int hi = arg_encode[fixP->tc_fix_data.arg_format].hi;
1004 int lo = arg_encode[fixP->tc_fix_data.arg_format].lo;
e9f53129
AM
1005 if (hi > lo && ((offsetT) val < lo || (offsetT) val > hi))
1006 as_bad_where (fixP->fx_file, fixP->fx_line,
1007 "Relocation doesn't fit. (relocation value = 0x%lx)",
1008 (long) val);
1009 }
1010
1011 switch (fixP->fx_r_type)
1012 {
1013 case BFD_RELOC_8:
1014 md_number_to_chars (place, val, 1);
1015 return;
1016
1017 case BFD_RELOC_16:
1018 md_number_to_chars (place, val, 2);
1019 return;
1020
1021 case BFD_RELOC_32:
1022 md_number_to_chars (place, val, 4);
1023 return;
1024
1025 case BFD_RELOC_64:
1026 md_number_to_chars (place, val, 8);
1027 return;
1028
1029 case BFD_RELOC_SPU_IMM7:
1030 res = (val & 0x7f) << 14;
1031 break;
1032
1033 case BFD_RELOC_SPU_IMM8:
1034 res = (val & 0xff) << 14;
1035 break;
1036
1037 case BFD_RELOC_SPU_IMM10:
1038 res = (val & 0x3ff) << 14;
1039 break;
1040
1041 case BFD_RELOC_SPU_IMM10W:
1042 res = (val & 0x3ff0) << 10;
1043 break;
1044
1045 case BFD_RELOC_SPU_IMM16:
1046 res = (val & 0xffff) << 7;
1047 break;
1048
1049 case BFD_RELOC_SPU_IMM16W:
1050 res = (val & 0x3fffc) << 5;
1051 break;
1052
1053 case BFD_RELOC_SPU_IMM18:
1054 res = (val & 0x3ffff) << 7;
1055 break;
1056
1057 case BFD_RELOC_SPU_PCREL9a:
1058 res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14);
1059 break;
1060
1061 case BFD_RELOC_SPU_PCREL9b:
1062 res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5);
1063 break;
1064
1065 case BFD_RELOC_SPU_PCREL16:
1066 res = (val & 0x3fffc) << 5;
1067 break;
1068
1069 default:
1070 as_bad_where (fixP->fx_file, fixP->fx_line,
1071 _("reloc %d not supported by object file format"),
1072 (int) fixP->fx_r_type);
1073 }
1074
1075 if (res != 0)
1076 {
1077 place[0] |= (res >> 24) & 0xff;
1078 place[1] |= (res >> 16) & 0xff;
1079 place[2] |= (res >> 8) & 0xff;
1080 place[3] |= (res) & 0xff;
1081 }
1082 }
1083}
This page took 0.087194 seconds and 4 git commands to generate.