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