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