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