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