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