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