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