1 /* tc-ldx.c -- Assemble for the DLX 2 Copyright 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 3 4 This file is part of GAS, the GNU Assembler. 5 6 GAS is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GAS is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GAS; see the file COPYING. If not, write to the Free 18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 19 02110-1301, USA. */ 20 21 /* Initially created by Kuang Hwa Lin, 3/20/2002. */ 22 23 #include "safe-ctype.h" 24 #include "as.h" 25 #include "tc-dlx.h" 26 #include "opcode/dlx.h" 27 28 /* Make it easier to clone this machine desc into another one. */ 29 #define machine_opcode dlx_opcode 30 #define machine_opcodes dlx_opcodes 31 #define machine_ip dlx_ip 32 #define machine_it dlx_it 33 34 #define NO_RELOC BFD_RELOC_NONE 35 #define RELOC_DLX_REL26 BFD_RELOC_DLX_JMP26 36 #define RELOC_DLX_16 BFD_RELOC_16 37 #define RELOC_DLX_REL16 BFD_RELOC_16_PCREL_S2 38 #define RELOC_DLX_HI16 BFD_RELOC_HI16_S 39 #define RELOC_DLX_LO16 BFD_RELOC_LO16 40 #define RELOC_DLX_VTINHERIT BFD_RELOC_VTABLE_INHERIT 41 #define RELOC_DLX_VTENTRY BFD_RELOC_VTABLE_ENTRY 42 43 /* handle of the OPCODE hash table */ 44 static struct hash_control *op_hash = NULL; 45 46 struct machine_it 47 { 48 char *error; 49 unsigned long opcode; 50 struct nlist *nlistp; 51 expressionS exp; 52 int pcrel; 53 int size; 54 int reloc_offset; /* Offset of reloc within insn. */ 55 int reloc; 56 int HI; 57 int LO; 58 } 59 the_insn; 60 61 /* This array holds the chars that always start a comment. If the 62 pre-processor is disabled, these aren't very useful. */ 63 const char comment_chars[] = ";"; 64 65 /* This array holds the chars that only start a comment at the beginning of 66 a line. If the line seems to have the form '# 123 filename' 67 .line and .file directives will appear in the pre-processed output. */ 68 /* Note that input_file.c hand checks for '#' at the beginning of the 69 first line of the input file. This is because the compiler outputs 70 #NO_APP at the beginning of its output. */ 71 /* Also note that comments like this one will always work. */ 72 const char line_comment_chars[] = "#"; 73 74 /* We needed an unused char for line separation to work around the 75 lack of macros, using sed and such. */ 76 const char line_separator_chars[] = "@"; 77 78 /* Chars that can be used to separate mant from exp in floating point nums. */ 79 const char EXP_CHARS[] = "eE"; 80 81 /* Chars that mean this number is a floating point constant. 82 As in 0f12.456 83 or 0d1.2345e12. */ 84 const char FLT_CHARS[] = "rRsSfFdDxXpP"; 85 86 static void 87 insert_sreg (char *regname, int regnum) 88 { 89 /* Must be large enough to hold the names of the special registers. */ 90 char buf[80]; 91 int i; 92 93 symbol_table_insert (symbol_new (regname, reg_section, (valueT) regnum, 94 &zero_address_frag)); 95 for (i = 0; regname[i]; i++) 96 buf[i] = ISLOWER (regname[i]) ? TOUPPER (regname[i]) : regname[i]; 97 buf[i] = '\0'; 98 99 symbol_table_insert (symbol_new (buf, reg_section, (valueT) regnum, 100 &zero_address_frag)); 101 } 102 103 /* Install symbol definitions for assorted special registers. 104 See MIPS Assembly Language Programmer's Guide page 1-4 */ 105 106 static void 107 define_some_regs (void) 108 { 109 /* Software representation. */ 110 insert_sreg ("zero", 0); 111 insert_sreg ("at", 1); 112 insert_sreg ("v0", 2); 113 insert_sreg ("v1", 3); 114 insert_sreg ("a0", 4); 115 insert_sreg ("a1", 5); 116 insert_sreg ("a2", 6); 117 insert_sreg ("a3", 7); 118 insert_sreg ("t0", 8); 119 insert_sreg ("t1", 9); 120 insert_sreg ("t2", 10); 121 insert_sreg ("t3", 11); 122 insert_sreg ("t4", 12); 123 insert_sreg ("t5", 13); 124 insert_sreg ("t6", 14); 125 insert_sreg ("t7", 15); 126 insert_sreg ("s0", 16); 127 insert_sreg ("s1", 17); 128 insert_sreg ("s2", 18); 129 insert_sreg ("s3", 19); 130 insert_sreg ("s4", 20); 131 insert_sreg ("s5", 21); 132 insert_sreg ("s6", 22); 133 insert_sreg ("s7", 23); 134 insert_sreg ("t8", 24); 135 insert_sreg ("t9", 25); 136 insert_sreg ("k0", 26); 137 insert_sreg ("k1", 27); 138 insert_sreg ("gp", 28); 139 insert_sreg ("sp", 29); 140 insert_sreg ("fp", 30); 141 insert_sreg ("ra", 31); 142 /* Special registers. */ 143 insert_sreg ("pc", 0); 144 insert_sreg ("npc", 1); 145 insert_sreg ("iad", 2); 146 } 147 148 /* Subroutine check the string to match an register. */ 149 150 static int 151 match_sft_register (char *name) 152 { 153 #define MAX_REG_NO 35 154 /* Currently we have 35 software registers defined - 155 we borrowed from MIPS. */ 156 static char *soft_reg[] = 157 { 158 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 159 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", 160 "s0", "s1", "s2", "s3", "s4", "s5", "s7", "k0", "k1", 161 "gp", "sp", "fp", "ra", "pc", "npc", "iad", 162 "EndofTab" /* End of the Table indicator */ 163 }; 164 char low_name[21], *ptr; 165 int idx; 166 167 for (ptr = name,idx = 0; *ptr != '\0'; ptr++) 168 low_name[idx++] = TOLOWER (*ptr); 169 170 low_name[idx] = '\0'; 171 idx = 0; 172 173 while (idx < MAX_REG_NO && strcmp (soft_reg[idx], & low_name [0])) 174 idx += 1; 175 176 return idx < MAX_REG_NO; 177 } 178 179 /* Subroutine check the string to match an register. */ 180 181 static int 182 is_ldst_registers (char *name) 183 { 184 char *ptr = name; 185 186 /* The first character of the register name got to be either %, $, r of R. */ 187 if ((ptr[0] == '%' || ptr[0] == '$' || ptr[0] == 'r' || ptr[0] == 'R') 188 && ISDIGIT ((unsigned char) ptr[1])) 189 return 1; 190 191 /* Now check the software register representation. */ 192 return match_sft_register (ptr); 193 } 194 195 /* Subroutine of s_proc so targets can choose a different default prefix. 196 If DEFAULT_PREFIX is NULL, use the target's "leading char". */ 197 198 static void 199 s_proc (int end_p) 200 { 201 /* Record the current function so that we can issue an error message for 202 misplaced .func,.endfunc, and also so that .endfunc needs no 203 arguments. */ 204 static char *current_name; 205 static char *current_label; 206 207 if (end_p) 208 { 209 if (current_name == NULL) 210 { 211 as_bad (_("missing .proc")); 212 ignore_rest_of_line (); 213 return; 214 } 215 216 current_name = current_label = NULL; 217 SKIP_WHITESPACE (); 218 while (!is_end_of_line[(unsigned char) *input_line_pointer]) 219 input_line_pointer++; 220 } 221 else 222 { 223 char *name, *label; 224 char delim1, delim2; 225 226 if (current_name != NULL) 227 { 228 as_bad (_(".endfunc missing for previous .proc")); 229 ignore_rest_of_line (); 230 return; 231 } 232 233 name = input_line_pointer; 234 delim1 = get_symbol_end (); 235 name = xstrdup (name); 236 *input_line_pointer = delim1; 237 SKIP_WHITESPACE (); 238 239 if (*input_line_pointer != ',') 240 { 241 char leading_char = 0; 242 243 leading_char = bfd_get_symbol_leading_char (stdoutput); 244 /* Missing entry point, use function's name with the leading 245 char prepended. */ 246 if (leading_char) 247 asprintf (&label, "%c%s", leading_char, name); 248 else 249 label = name; 250 } 251 else 252 { 253 ++input_line_pointer; 254 SKIP_WHITESPACE (); 255 label = input_line_pointer; 256 delim2 = get_symbol_end (); 257 label = xstrdup (label); 258 *input_line_pointer = delim2; 259 } 260 261 current_name = name; 262 current_label = label; 263 } 264 demand_empty_rest_of_line (); 265 } 266 267 /* This function is called once, at assembler startup time. It should 268 set up all the tables, etc., that the MD part of the assembler will 269 need. */ 270 271 void 272 md_begin (void) 273 { 274 const char *retval = NULL; 275 int lose = 0; 276 unsigned int i; 277 278 /* Create a new hash table. */ 279 op_hash = hash_new (); 280 281 /* Hash up all the opcodes for fast use later. */ 282 for (i = 0; i < num_dlx_opcodes; i++) 283 { 284 const char *name = machine_opcodes[i].name; 285 286 retval = hash_insert (op_hash, name, (void *) &machine_opcodes[i]); 287 288 if (retval != NULL) 289 { 290 fprintf (stderr, "internal error: can't hash `%s': %s\n", 291 machine_opcodes[i].name, retval); 292 lose = 1; 293 } 294 } 295 296 if (lose) 297 as_fatal (_("Broken assembler. No assembly attempted.")); 298 299 define_some_regs (); 300 } 301 302 /* This function will check the opcode and return 1 if the opcode is one 303 of the load/store instruction, and it will fix the operand string to 304 the standard form so we can use the standard parse_operand routine. */ 305 306 #define READ_OP 0x100 307 #define WRITE_OP 0x200 308 static char iBuf[81]; 309 310 static char * 311 dlx_parse_loadop (char * str) 312 { 313 char *ptr = str; 314 int idx = 0; 315 316 /* The last pair of ()/[] is the register, all other are the 317 reloc displacement, and if there is a register then it ought 318 to have a pair of ()/[] 319 This is not necessarily true, what if the load instruction come 320 without the register and with %hi/%lo modifier? */ 321 for (idx = 0; idx < 72 && ptr[idx] != '\0'; idx++) 322 ; 323 324 if (idx == 72) 325 { 326 badoperand_load: 327 as_bad (_("Bad operand for a load instruction: <%s>"), str); 328 return NULL; 329 } 330 else 331 { 332 int i, pb = 0; 333 int m2 = 0; 334 char rs1[7], rd[7], endm, match = '0'; 335 char imm[72]; 336 337 idx -= 1; 338 switch (str[idx]) 339 { 340 case ')': 341 match = '('; 342 endm = ')'; 343 break; 344 case ']': 345 match = '['; 346 endm = ']'; 347 break; 348 default: 349 /* No register indicated, fill in zero. */ 350 rs1[0] = 'r'; 351 rs1[1] = '0'; 352 rs1[2] = '\0'; 353 match = 0; 354 endm = 0; 355 m2 = 1; 356 } 357 358 if (!m2) 359 { 360 /* Searching for (/[ which will match the ]/). */ 361 for (pb = idx - 1; str[pb] != match; pb -= 1) 362 /* Match can only be either '[' or '(', if it is 363 '(' then this can be a normal expression, we'll treat 364 it as an operand. */ 365 if (str[pb] == endm || pb < (idx - 5)) 366 goto load_no_rs1; 367 pb += 1; 368 369 for (i = 0; (pb + i) < idx; i++) 370 rs1[i] = str[pb+i]; 371 372 rs1[i] = '\0'; 373 374 if (is_ldst_registers (& rs1[0])) 375 /* Point to the last character of the imm. */ 376 pb -= 1; 377 else 378 { 379 load_no_rs1: 380 if (match == '[') 381 goto badoperand_load; 382 /* No register indicated, fill in zero and restore the imm. */ 383 rs1[0] = 'r'; 384 rs1[1] = '0'; 385 rs1[2] = '\0'; 386 m2 = 1; 387 } 388 } 389 390 /* Duplicate the first register. */ 391 for (i = 0; i < 7 && str[i] != ','; i++) 392 rd[i] = ptr[i]; 393 394 if (str[i] != ',') 395 goto badoperand_load; 396 else 397 rd[i] = '\0'; 398 399 /* Copy the immd. */ 400 if (m2) 401 /* Put the '\0' back in. */ 402 pb = idx + 1; 403 404 for (i++, m2 = 0; i < pb; m2++,i++) 405 imm[m2] = ptr[i]; 406 407 imm[m2] = '\0'; 408 409 /* Assemble the instruction to gas internal format. */ 410 for (i = 0; rd[i] != '\0'; i++) 411 iBuf[i] = rd[i]; 412 413 iBuf[i++] = ','; 414 415 for (pb = 0 ; rs1[pb] != '\0'; i++, pb++) 416 iBuf[i] = rs1[pb]; 417 418 iBuf[i++] = ','; 419 420 for (pb = 0; imm[pb] != '\0'; i++, pb++) 421 iBuf[i] = imm[pb]; 422 423 iBuf[i] = '\0'; 424 return iBuf; 425 } 426 } 427 428 static char * 429 dlx_parse_storeop (char * str) 430 { 431 char *ptr = str; 432 int idx = 0; 433 434 /* Search for the ','. */ 435 for (idx = 0; idx < 72 && ptr[idx] != ','; idx++) 436 ; 437 438 if (idx == 72) 439 { 440 badoperand_store: 441 as_bad (_("Bad operand for a store instruction: <%s>"), str); 442 return NULL; 443 } 444 else 445 { 446 /* idx now points to the ','. */ 447 int i, pb = 0; 448 int comma = idx; 449 int m2 = 0; 450 char rs1[7], rd[7], endm, match = '0'; 451 char imm[72]; 452 453 /* Now parse the '(' and ')', and make idx point to ')'. */ 454 idx -= 1; 455 switch (str[idx]) 456 { 457 case ')': 458 match = '('; 459 endm = ')'; 460 break; 461 case ']': 462 match = '['; 463 endm = ']'; 464 break; 465 default: 466 /* No register indicated, fill in zero. */ 467 rs1[0] = 'r'; 468 rs1[1] = '0'; 469 rs1[2] = '\0'; 470 match = 0; 471 endm = 0; 472 m2 = 1; 473 } 474 475 if (!m2) 476 { 477 /* Searching for (/[ which will match the ]/). */ 478 for (pb = idx - 1; str[pb] != match; pb -= 1) 479 if (pb < (idx - 5) || str[pb] == endm) 480 goto store_no_rs1; 481 pb += 1; 482 483 for (i = 0; (pb + i) < idx; i++) 484 rs1[i] = str[pb + i]; 485 486 rs1[i] = '\0'; 487 488 if (is_ldst_registers (& rs1[0])) 489 /* Point to the last character of the imm. */ 490 pb -= 1; 491 else 492 { 493 store_no_rs1: 494 if (match == '[') 495 goto badoperand_store; 496 497 /* No register indicated, fill in zero and restore the imm. */ 498 rs1[0] = 'r'; 499 rs1[1] = '0'; 500 rs1[2] = '\0'; 501 pb = comma; 502 } 503 } 504 else 505 /* No register was specified. */ 506 pb = comma; 507 508 /* Duplicate the first register. */ 509 for (i = comma + 1; (str[i] == ' ' || str[i] == '\t'); i++) 510 ; 511 512 for (m2 = 0; (m2 < 7 && str[i] != '\0'); i++, m2++) 513 { 514 if (str[i] != ' ' && str[i] != '\t') 515 rd[m2] = str[i]; 516 else 517 goto badoperand_store; 518 } 519 520 if (str[i] != '\0') 521 goto badoperand_store; 522 else 523 rd[m2] = '\0'; 524 525 /* Copy the immd. */ 526 for (i = 0; i < pb; i++) 527 imm[i] = ptr[i]; 528 529 imm[i] = '\0'; 530 531 /* Assemble the instruction to gas internal format. */ 532 for (i = 0; rd[i] != '\0'; i++) 533 iBuf[i] = rd[i]; 534 iBuf[i++] = ','; 535 for (pb = 0 ; rs1[pb] != '\0'; i++, pb++) 536 iBuf[i] = rs1[pb]; 537 iBuf[i++] = ','; 538 for (pb = 0; imm[pb] != '\0'; i++, pb++) 539 iBuf[i] = imm[pb]; 540 iBuf[i] = '\0'; 541 return iBuf; 542 } 543 } 544 545 static char * 546 fix_ld_st_operand (unsigned long opcode, char* str) 547 { 548 /* Check the opcode. */ 549 switch ((int) opcode) 550 { 551 case LBOP: 552 case LBUOP: 553 case LSBUOP: 554 case LHOP: 555 case LHUOP: 556 case LSHUOP: 557 case LWOP: 558 case LSWOP: 559 return dlx_parse_loadop (str); 560 case SBOP: 561 case SHOP: 562 case SWOP: 563 return dlx_parse_storeop (str); 564 default: 565 return str; 566 } 567 } 568 569 static int 570 hilo_modifier_ok (char *s) 571 { 572 char *ptr = s; 573 int idx, count = 1; 574 575 if (*ptr != '(') 576 return 1; 577 578 for (idx = 1; ptr[idx] != '\0' && ptr[idx] != '[' && idx < 73; idx += 1) 579 { 580 if (count == 0) 581 return count; 582 583 if (ptr[idx] == '(') 584 count += 1; 585 586 if (ptr[idx] == ')') 587 count -= 1; 588 } 589 590 return (count == 0) ? 1:0; 591 } 592 593 static char * 594 parse_operand (char *s, expressionS *operandp) 595 { 596 char *save = input_line_pointer; 597 char *new; 598 599 the_insn.HI = the_insn.LO = 0; 600 601 /* Search for %hi and %lo, make a mark and skip it. */ 602 if (strncmp (s, "%hi", 3) == 0) 603 { 604 s += 3; 605 the_insn.HI = 1; 606 } 607 else 608 { 609 if (strncmp (s, "%lo", 3) == 0) 610 { 611 s += 3; 612 the_insn.LO = 1; 613 } 614 else 615 the_insn.LO = 0; 616 } 617 618 if (the_insn.HI || the_insn.LO) 619 { 620 if (!hilo_modifier_ok (s)) 621 as_bad (_("Expression Error for operand modifier %%hi/%%lo\n")); 622 } 623 624 /* Check for the % and $ register representation */ 625 if ((s[0] == '%' || s[0] == '$' || s[0] == 'r' || s[0] == 'R') 626 && ISDIGIT ((unsigned char) s[1])) 627 { 628 /* We have a numeric register expression. No biggy. */ 629 s += 1; 630 input_line_pointer = s; 631 (void) expression (operandp); 632 if (operandp->X_op != O_constant 633 || operandp->X_add_number > 31) 634 as_bad (_("Invalid expression after %%%%\n")); 635 operandp->X_op = O_register; 636 } 637 else 638 { 639 /* Normal operand parsing. */ 640 input_line_pointer = s; 641 (void) expression (operandp); 642 } 643 644 new = input_line_pointer; 645 input_line_pointer = save; 646 return new; 647 } 648 649 /* Instruction parsing. Takes a string containing the opcode. 650 Operands are at input_line_pointer. Output is in the_insn. 651 Warnings or errors are generated. */ 652 653 static void 654 machine_ip (char *str) 655 { 656 char *s; 657 const char *args; 658 struct machine_opcode *insn; 659 char *argsStart; 660 unsigned long opcode; 661 expressionS the_operand; 662 expressionS *operand = &the_operand; 663 unsigned int reg, reg_shift = 0; 664 665 /* Fixup the opcode string to all lower cases, and also 666 allow numerical digits. */ 667 s = str; 668 669 if (ISALPHA (*s)) 670 for (; ISALNUM (*s); ++s) 671 if (ISUPPER (*s)) 672 *s = TOLOWER (*s); 673 674 switch (*s) 675 { 676 case '\0': 677 break; 678 679 /* FIXME-SOMEDAY more whitespace. */ 680 case ' ': 681 *s++ = '\0'; 682 break; 683 684 default: 685 as_bad (_("Unknown opcode: `%s'"), str); 686 return; 687 } 688 689 /* Hash the opcode, insn will have the string from opcode table. 690 also initialized the_insn struct. */ 691 if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL) 692 { 693 /* Handle the ret and return macro here. */ 694 if ((strcmp (str, "ret") == 0) || (strcmp (str, "return") == 0)) 695 { 696 memset (&the_insn, '\0', sizeof (the_insn)); 697 the_insn.reloc = NO_RELOC; 698 the_insn.pcrel = 0; 699 the_insn.opcode = 700 (unsigned long)(JROP | 0x03e00000); /* 0x03e00000 = r31 << 21 */ 701 } 702 else 703 as_bad (_("Unknown opcode `%s'."), str); 704 705 return; 706 } 707 708 argsStart = s; 709 opcode = insn->opcode; 710 memset (&the_insn, '\0', sizeof (the_insn)); 711 the_insn.reloc = NO_RELOC; 712 the_insn.pcrel = 0; 713 714 /* Set the sip reloc HI16 flag. */ 715 if (!set_dlx_skip_hi16_flag (1)) 716 as_bad (_("Can not set dlx_skip_hi16_flag")); 717 718 /* Fix the operand string if it is one of load store instructions. */ 719 s = fix_ld_st_operand (opcode, s); 720 721 /* Build the opcode, checking as we go to make sure that the 722 operands match. 723 If an operand matches, we modify the_insn or opcode appropriately, 724 and do a "continue". If an operand fails to match, we "break". */ 725 if (insn->args[0] != '\0' && insn->args[0] != 'N') 726 { 727 /* Prime the pump. */ 728 if (*s == '\0') 729 { 730 as_bad (_("Missing arguments for opcode <%s>."), str); 731 return; 732 } 733 else 734 s = parse_operand (s, operand); 735 } 736 else if (insn->args[0] == 'N') 737 { 738 /* Clean up the insn and done! */ 739 the_insn.opcode = opcode; 740 return; 741 } 742 743 /* Parse through the args (this is from opcode table), *s point to 744 the current character of the instruction stream. */ 745 for (args = insn->args;; ++args) 746 { 747 switch (*args) 748 { 749 /* End of Line. */ 750 case '\0': 751 /* End of args. */ 752 if (*s == '\0') 753 { 754 /* We are truly done. */ 755 the_insn.opcode = opcode; 756 /* Clean up the HI and LO mark. */ 757 the_insn.HI = 0; 758 the_insn.LO = 0; 759 return; 760 } 761 762 the_insn.HI = 0; 763 the_insn.LO = 0; 764 as_bad (_("Too many operands: %s"), s); 765 break; 766 767 /* ',' Args separator */ 768 case ',': 769 /* Must match a comma. */ 770 if (*s++ == ',') 771 { 772 /* Parse next operand. */ 773 s = parse_operand (s, operand); 774 continue; 775 } 776 break; 777 778 /* It can be a 'a' register or 'i' operand. */ 779 case 'P': 780 /* Macro move operand/reg. */ 781 if (operand->X_op == O_register) 782 { 783 /* Its a register. */ 784 reg_shift = 21; 785 goto general_reg; 786 } 787 788 /* The immediate 16 bits literal, bit 0-15. */ 789 case 'i': 790 /* offset, unsigned. */ 791 case 'I': 792 /* offset, signed. */ 793 if (operand->X_op == O_constant) 794 { 795 if (the_insn.HI) 796 operand->X_add_number >>= 16; 797 798 opcode |= operand->X_add_number & 0xFFFF; 799 800 if (the_insn.HI && the_insn.LO) 801 as_bad (_("Both the_insn.HI and the_insn.LO are set : %s"), s); 802 else 803 { 804 the_insn.HI = 0; 805 the_insn.LO = 0; 806 } 807 continue; 808 } 809 810 the_insn.reloc = (the_insn.HI) ? RELOC_DLX_HI16 811 : (the_insn.LO ? RELOC_DLX_LO16 : RELOC_DLX_16); 812 the_insn.reloc_offset = 2; 813 the_insn.size = 2; 814 the_insn.pcrel = 0; 815 the_insn.exp = * operand; 816 the_insn.HI = 0; 817 the_insn.LO = 0; 818 continue; 819 820 case 'd': 821 /* offset, signed. */ 822 if (operand->X_op == O_constant) 823 { 824 opcode |= operand->X_add_number & 0xFFFF; 825 continue; 826 } 827 the_insn.reloc = RELOC_DLX_REL16; 828 the_insn.reloc_offset = 0; /* BIG-ENDIAN Byte 3 of insn. */ 829 the_insn.size = 4; 830 the_insn.pcrel = 1; 831 the_insn.exp = *operand; 832 continue; 833 834 /* The immediate 26 bits literal, bit 0-25. */ 835 case 'D': 836 /* offset, signed. */ 837 if (operand->X_op == O_constant) 838 { 839 opcode |= operand->X_add_number & 0x3FFFFFF; 840 continue; 841 } 842 the_insn.reloc = RELOC_DLX_REL26; 843 the_insn.reloc_offset = 0; /* BIG-ENDIAN Byte 3 of insn. */ 844 the_insn.size = 4; 845 the_insn.pcrel = 1; 846 the_insn.exp = *operand; 847 continue; 848 849 /* Type 'a' Register. */ 850 case 'a': 851 /* A general register at bits 21-25, rs1. */ 852 reg_shift = 21; 853 goto general_reg; 854 855 /* Type 'b' Register. */ 856 case 'b': 857 /* A general register at bits 16-20, rs2/rd. */ 858 reg_shift = 16; 859 goto general_reg; 860 861 /* Type 'c' Register. */ 862 case 'c': 863 /* A general register at bits 11-15, rd. */ 864 reg_shift = 11; 865 866 general_reg: 867 know (operand->X_add_symbol == 0); 868 know (operand->X_op_symbol == 0); 869 reg = operand->X_add_number; 870 if (reg & 0xffffffe0) 871 as_fatal (_("failed regnum sanity check.")); 872 else 873 /* Got the register, now figure out where it goes in the opcode. */ 874 opcode |= reg << reg_shift; 875 876 switch (*args) 877 { 878 case 'a': 879 case 'b': 880 case 'c': 881 case 'P': 882 continue; 883 } 884 as_fatal (_("failed general register sanity check.")); 885 break; 886 887 default: 888 BAD_CASE (*args); 889 } 890 891 /* Types or values of args don't match. */ 892 as_bad ("Invalid operands"); 893 return; 894 } 895 } 896 897 /* Assemble a single instruction. Its label has already been handled 898 by the generic front end. We just parse opcode and operands, and 899 produce the bytes of data and relocation. */ 900 901 void 902 md_assemble (char *str) 903 { 904 char *toP; 905 fixS *fixP; 906 bit_fixS *bitP; 907 908 know (str); 909 machine_ip (str); 910 toP = frag_more (4); 911 /* Put out the opcode. */ 912 md_number_to_chars (toP, the_insn.opcode, 4); 913 914 /* Put out the symbol-dependent stuff. */ 915 if (the_insn.reloc != NO_RELOC) 916 { 917 fixP = fix_new_exp (frag_now, 918 (toP - frag_now->fr_literal + the_insn.reloc_offset), 919 the_insn.size, & the_insn.exp, the_insn.pcrel, 920 the_insn.reloc); 921 922 /* Turn off complaints that the addend is 923 too large for things like foo+100000@ha. */ 924 switch (the_insn.reloc) 925 { 926 case RELOC_DLX_HI16: 927 case RELOC_DLX_LO16: 928 fixP->fx_no_overflow = 1; 929 break; 930 default: 931 break; 932 } 933 934 switch (fixP->fx_r_type) 935 { 936 case RELOC_DLX_REL26: 937 bitP = malloc (sizeof (bit_fixS)); 938 bitP->fx_bit_size = 26; 939 bitP->fx_bit_offset = 25; 940 bitP->fx_bit_base = the_insn.opcode & 0xFC000000; 941 bitP->fx_bit_base_adj = 0; 942 bitP->fx_bit_max = 0; 943 bitP->fx_bit_min = 0; 944 bitP->fx_bit_add = 0x03FFFFFF; 945 fixP->fx_bit_fixP = bitP; 946 break; 947 case RELOC_DLX_LO16: 948 case RELOC_DLX_REL16: 949 bitP = malloc (sizeof (bit_fixS)); 950 bitP->fx_bit_size = 16; 951 bitP->fx_bit_offset = 15; 952 bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000; 953 bitP->fx_bit_base_adj = 0; 954 bitP->fx_bit_max = 0; 955 bitP->fx_bit_min = 0; 956 bitP->fx_bit_add = 0x0000FFFF; 957 fixP->fx_bit_fixP = bitP; 958 break; 959 case RELOC_DLX_HI16: 960 bitP = malloc (sizeof (bit_fixS)); 961 bitP->fx_bit_size = 16; 962 bitP->fx_bit_offset = 15; 963 bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000; 964 bitP->fx_bit_base_adj = 0; 965 bitP->fx_bit_max = 0; 966 bitP->fx_bit_min = 0; 967 bitP->fx_bit_add = 0x0000FFFF; 968 fixP->fx_bit_fixP = bitP; 969 break; 970 default: 971 fixP->fx_bit_fixP = NULL; 972 break; 973 } 974 } 975 } 976 977 /* This is identical to the md_atof in m68k.c. I think this is right, 978 but I'm not sure. 979 980 Turn a string in input_line_pointer into a floating point constant 981 of type TYPE, and store the appropriate bytes in *LITP. The number 982 of LITTLENUMS emitted is stored in *SIZEP. An error message is 983 returned, or NULL on OK. */ 984 /* Dlx will not use it anyway, so I just leave it here for now. */ 985 986 /* Equal to MAX_PRECISION in atof-ieee.c. */ 987 #define MAX_LITTLENUMS 6 988 989 char * 990 md_atof (int type, char *litP, int *sizeP) 991 { 992 int prec; 993 LITTLENUM_TYPE words[MAX_LITTLENUMS]; 994 LITTLENUM_TYPE *wordP; 995 char *t; 996 997 switch (type) 998 { 999 case 'f': 1000 case 'F': 1001 case 's': 1002 case 'S': 1003 prec = 2; 1004 break; 1005 1006 case 'd': 1007 case 'D': 1008 case 'r': 1009 case 'R': 1010 prec = 4; 1011 break; 1012 1013 case 'x': 1014 case 'X': 1015 prec = 6; 1016 break; 1017 1018 case 'p': 1019 case 'P': 1020 prec = 6; 1021 break; 1022 1023 default: 1024 *sizeP = 0; 1025 return "Bad call to MD_ATOF()"; 1026 } 1027 1028 t = atof_ieee (input_line_pointer, type, words); 1029 if (t) 1030 input_line_pointer = t; 1031 1032 *sizeP = prec * sizeof (LITTLENUM_TYPE); 1033 1034 for (wordP = words; prec--;) 1035 { 1036 md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); 1037 litP += sizeof (LITTLENUM_TYPE); 1038 } 1039 1040 return 0; 1041 } 1042 1043 /* Write out big-endian. */ 1044 void 1045 md_number_to_chars (char *buf, valueT val, int n) 1046 { 1047 number_to_chars_bigendian (buf, val, n); 1048 } 1049 1050 bfd_boolean 1051 md_dlx_fix_adjustable (fixS *fixP) 1052 { 1053 /* We need the symbol name for the VTABLE entries. */ 1054 return (fixP->fx_r_type != BFD_RELOC_VTABLE_INHERIT 1055 && fixP->fx_r_type != BFD_RELOC_VTABLE_ENTRY); 1056 } 1057 1058 void 1059 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) 1060 { 1061 long val = *valP; 1062 char *place = fixP->fx_where + fixP->fx_frag->fr_literal; 1063 1064 switch (fixP->fx_r_type) 1065 { 1066 case RELOC_DLX_LO16: 1067 case RELOC_DLX_REL16: 1068 if (fixP->fx_bit_fixP != NULL) 1069 { 1070 val = (val & 0x0000FFFF) | fixP->fx_bit_fixP->fx_bit_base; 1071 free (fixP->fx_bit_fixP); 1072 fixP->fx_bit_fixP = NULL; 1073 } 1074 #ifdef DEBUG 1075 else 1076 know ((fixP->fx_bit_fixP != NULL)); 1077 #endif 1078 break; 1079 1080 case RELOC_DLX_HI16: 1081 if (fixP->fx_bit_fixP != NULL) 1082 { 1083 val = (val >> 16) | fixP->fx_bit_fixP->fx_bit_base; 1084 free (fixP->fx_bit_fixP); 1085 fixP->fx_bit_fixP = NULL; 1086 } 1087 #ifdef DEBUG 1088 else 1089 know ((fixP->fx_bit_fixP != NULL)); 1090 #endif 1091 break; 1092 1093 case RELOC_DLX_REL26: 1094 if (fixP->fx_bit_fixP != NULL) 1095 { 1096 val = (val & 0x03FFFFFF) | fixP->fx_bit_fixP->fx_bit_base; 1097 free (fixP->fx_bit_fixP); 1098 fixP->fx_bit_fixP = NULL; 1099 } 1100 #ifdef DEBUG 1101 else 1102 know ((fixP->fx_bit_fixP != NULL)); 1103 #endif 1104 break; 1105 1106 case BFD_RELOC_VTABLE_INHERIT: 1107 /* This borrowed from tc-ppc.c on a whim. */ 1108 fixP->fx_done = 0; 1109 if (fixP->fx_addsy 1110 && !S_IS_DEFINED (fixP->fx_addsy) 1111 && !S_IS_WEAK (fixP->fx_addsy)) 1112 S_SET_WEAK (fixP->fx_addsy); 1113 return; 1114 1115 case BFD_RELOC_VTABLE_ENTRY: 1116 fixP->fx_done = 0; 1117 return; 1118 1119 default: 1120 break; 1121 } 1122 1123 number_to_chars_bigendian (place, val, fixP->fx_size); 1124 if (fixP->fx_addsy == NULL) 1125 fixP->fx_done = 1; 1126 } 1127 1128 const char *md_shortopts = ""; 1129 1130 struct option md_longopts[] = 1131 { 1132 {NULL, no_argument, NULL, 0} 1133 }; 1134 1135 size_t md_longopts_size = sizeof (md_longopts); 1136 1137 int 1138 md_parse_option (int c ATTRIBUTE_UNUSED, 1139 char *arg ATTRIBUTE_UNUSED) 1140 { 1141 return 0; 1142 } 1143 1144 void 1145 md_show_usage (FILE *stream ATTRIBUTE_UNUSED) 1146 { 1147 } 1148 1149 /* This is called when a line is unrecognized. */ 1150 1151 int 1152 dlx_unrecognized_line (int c) 1153 { 1154 int lab; 1155 char *s; 1156 1157 if (c != '$' || ! ISDIGIT ((unsigned char) input_line_pointer[0])) 1158 return 0; 1159 1160 s = input_line_pointer; 1161 1162 lab = 0; 1163 while (ISDIGIT ((unsigned char) *s)) 1164 { 1165 lab = lab * 10 + *s - '0'; 1166 ++s; 1167 } 1168 1169 if (*s != ':') 1170 /* Not a label definition. */ 1171 return 0; 1172 1173 if (dollar_label_defined (lab)) 1174 { 1175 as_bad (_("label \"$%d\" redefined"), lab); 1176 return 0; 1177 } 1178 1179 define_dollar_label (lab); 1180 colon (dollar_label_name (lab, 0)); 1181 input_line_pointer = s + 1; 1182 1183 return 1; 1184 } 1185 1186 /* Default the values of symbols known that should be "predefined". We 1187 don't bother to predefine them unless you actually use one, since there 1188 are a lot of them. */ 1189 1190 symbolS * 1191 md_undefined_symbol (char *name ATTRIBUTE_UNUSED) 1192 { 1193 return NULL; 1194 } 1195 1196 /* Parse an operand that is machine-specific, the function was called 1197 in expr.c by operand() function, when everything failed before it 1198 call a quit. */ 1199 1200 void 1201 md_operand (expressionS* expressionP) 1202 { 1203 /* Check for the #number representation */ 1204 if (input_line_pointer[0] == '#' && 1205 ISDIGIT ((unsigned char) input_line_pointer[1])) 1206 { 1207 /* We have a numeric number expression. No biggy. */ 1208 input_line_pointer += 1; /* Skip # */ 1209 1210 (void) expression (expressionP); 1211 1212 if (expressionP->X_op != O_constant) 1213 as_bad (_("Invalid expression after # number\n")); 1214 } 1215 1216 return; 1217 } 1218 1219 /* Round up a section size to the appropriate boundary. */ 1220 1221 valueT 1222 md_section_align (segT segment ATTRIBUTE_UNUSED, 1223 valueT size) 1224 { 1225 /* Byte alignment is fine. */ 1226 return size; 1227 } 1228 1229 /* Exactly what point is a PC-relative offset relative TO? 1230 On the 29000, they're relative to the address of the instruction, 1231 which we have set up as the address of the fixup too. */ 1232 1233 long 1234 md_pcrel_from (fixS* fixP) 1235 { 1236 return 4 + fixP->fx_where + fixP->fx_frag->fr_address; 1237 } 1238 1239 /* Translate internal representation of relocation info to BFD target 1240 format. 1241 FIXME: To what extent can we get all relevant targets to use this? 1242 The above FIXME is from a29k, but I think it is also needed here. */ 1243 1244 arelent * 1245 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, 1246 fixS *fixP) 1247 { 1248 arelent * reloc; 1249 1250 reloc = xmalloc (sizeof (arelent)); 1251 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); 1252 1253 if (reloc->howto == NULL) 1254 { 1255 as_bad_where (fixP->fx_file, fixP->fx_line, 1256 "internal error: can't export reloc type %d (`%s')", 1257 fixP->fx_r_type, 1258 bfd_get_reloc_code_name (fixP->fx_r_type)); 1259 return NULL; 1260 } 1261 1262 assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); 1263 1264 reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); 1265 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); 1266 reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; 1267 1268 if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) 1269 reloc->address = fixP->fx_offset; 1270 reloc->addend = 0; 1271 1272 return reloc; 1273 } 1274 1275 const pseudo_typeS 1276 dlx_pseudo_table[] = 1277 { 1278 /* Some additional ops that are used by gcc-dlx. */ 1279 {"asciiz", stringer, 1}, 1280 {"half", cons, 2}, 1281 {"dword", cons, 8}, 1282 {"word", cons, 4}, 1283 {"proc", s_proc, 0}, 1284 {"endproc", s_proc, 1}, 1285 {NULL, NULL, 0} 1286 }; 1287 1288 void 1289 dlx_pop_insert (void) 1290 { 1291 pop_insert (dlx_pseudo_table); 1292 return ; 1293 } 1294 1295