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