1 1.1 skrll /* spu.c -- Assembler for the IBM Synergistic Processing Unit (SPU) 2 1.1 skrll 3 1.1.1.10 christos Copyright (C) 2006-2026 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