|
|
1.1 ! root 1: /* i860.c -- Assemble for the i860 ! 2: Copyright (C) 1989 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 1, 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 ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: ! 21: #include <stdio.h> ! 22: #include <string.h> ! 23: #include <ctype.h> ! 24: #include <mach-o/i860/reloc.h> ! 25: ! 26: #include "i860-opcode.h" ! 27: #include "as.h" ! 28: #include "flonum.h" ! 29: #include "expr.h" ! 30: #include "hash.h" ! 31: #include "frags.h" ! 32: #include "fixes.h" ! 33: #include "read.h" ! 34: #include "md.h" ! 35: #include "symbols.h" ! 36: #include "messages.h" ! 37: #include "sections.h" ! 38: ! 39: /* ! 40: * These are the default cputype and cpusubtype for the i860 architecture. ! 41: */ ! 42: const cpu_type_t md_cputype = CPU_TYPE_I860; ! 43: cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_I860_ALL; ! 44: ! 45: /* ! 46: * This is the byte sex for the i860 architecture. The chip is running in ! 47: * big endian mode so the assembler puts out the entire file (instructions ! 48: * included) in big endian. When the program is loaded in memory to be run ! 49: * the program doing the loading byte swaps the fix width instructions. If ! 50: * this is not to be done by the loading program then BYTE_SWAP can be defined ! 51: * in here that will put out the instructiona in little endian in the object ! 52: * file. ! 53: */ ! 54: const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX; ! 55: ! 56: static int i860_ip( ! 57: char *str); ! 58: static void md_insn_to_chars( ! 59: unsigned char *buf, ! 60: long val, ! 61: int n); ! 62: ! 63: const relax_typeS md_relax_table[] = { 0 }; ! 64: ! 65: /* handle of the OPCODE hash table */ ! 66: static struct hash_control *op_hash = NULL; ! 67: ! 68: static void s_dual( ! 69: int mode); ! 70: static void s_i860_align( ! 71: int value); ! 72: static void s_i860_org( ! 73: int value); ! 74: ! 75: const pseudo_typeS md_pseudo_table[] = { ! 76: { "float", float_cons, 'f' }, ! 77: { "int", cons, 4 }, ! 78: { "align", s_i860_align, 0 }, /* Alignment is in bytes */ ! 79: { "blkb", s_space, 0 }, /* Reserve space, in bytes */ ! 80: { "dual", s_dual, 1 }, /* Dual insn mode crock */ ! 81: { "enddual",s_dual, 0 }, ! 82: { "extern", s_globl, 0 }, /* as860 equiv of .globl */ ! 83: { "ln", s_line, 0 }, /* as860 equiv of .line */ ! 84: { "org", s_i860_org, 0 }, ! 85: #ifndef NeXT ! 86: { "quad", big_cons, 16 }, /* A quad is 16 bytes on 860 */ ! 87: #endif /* NeXT */ ! 88: { "string", stringer, 1 }, /* as860 equiv of .asciz */ ! 89: { NULL, 0, 0 }, ! 90: }; ! 91: ! 92: static int dual_insn_mode = 0; ! 93: ! 94: /* This array holds the chars that always start a comment. If the ! 95: pre-processor is disabled, these aren't very useful */ ! 96: const char md_comment_chars[] = "|!"; ! 97: ! 98: /* This array holds the chars that only start a comment at the beginning of ! 99: a line. If the line seems to have the form '# 123 filename' ! 100: .line and .file directives will appear in the pre-processed output */ ! 101: /* Note that input_file.c hand checks for '#' at the beginning of the ! 102: first line of the input file. This is because the compiler outputs ! 103: #NO_APP at the beginning of its output. */ ! 104: /* Also note that a '/' followed by a '*' will always start a comment */ ! 105: const char md_line_comment_chars[] = "#"; ! 106: ! 107: /* Chars that can be used to separate mant from exp in floating point nums */ ! 108: const char md_EXP_CHARS[] = "eE"; ! 109: ! 110: /* Chars that mean this number is a floating point constant */ ! 111: /* As in 0f12.456 */ ! 112: /* or 0d1.2345e12 */ ! 113: const char md_FLT_CHARS[] = "rRsSfFdDxXpP"; ! 114: ! 115: /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be ! 116: changed in read.c . Ideally it shouldn't have to know about it at all, ! 117: but nothing is ideal around here. ! 118: */ ! 119: int size_reloc_info = sizeof(struct relocation_info); ! 120: ! 121: static unsigned char octal[256]; ! 122: #define isoctal(c) octal[c] ! 123: static unsigned char toHex[256]; ! 124: ! 125: /* Local fatal error flag. Used to bomb assembler in md_end after scanning input */ ! 126: static int I860_errors; ! 127: ! 128: static int insn_count; /* Track insns assembled, as a word count */ ! 129: ! 130: struct i860_it { ! 131: char *error; ! 132: unsigned long opcode; ! 133: struct nlist *nlistp; ! 134: expressionS exp; ! 135: int pcrel; ! 136: enum reloc_type_i860 reloc; ! 137: }; ! 138: static struct i860_it the_insn; ! 139: ! 140: #ifdef I860_DEBUG ! 141: static void print_insn( ! 142: struct i860_it *insn); ! 143: #endif /* I860_DEBUG */ ! 144: ! 145: static int getExpression( ! 146: char *str); ! 147: static char *expr_end; ! 148: ! 149: /* Flags returned by i860_ip() */ ! 150: #define INSERT_NOP 0x00000001 ! 151: ! 152: static ! 153: void ! 154: s_dual( ! 155: int mode) ! 156: { ! 157: dual_insn_mode = mode; ! 158: } ! 159: ! 160: static ! 161: void ! 162: s_i860_align( ! 163: int value) ! 164: { ! 165: register unsigned int temp; ! 166: register long int temp_fill; ! 167: unsigned int i = 0; ! 168: unsigned int bytes; ! 169: char *toP; ! 170: ! 171: bytes = temp = get_absolute_expression (); ! 172: #define MAX_ALIGNMENT (1 << 15) ! 173: if ( temp > MAX_ALIGNMENT ) { ! 174: as_warn("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT); ! 175: } ! 176: ! 177: /* ! 178: * For the i860, `.align (1<<n)' actually means `.align n' ! 179: * so we have to convert it. ! 180: */ ! 181: if (temp != 0) { ! 182: for (i = 0; (temp & 1) == 0; temp >>= 1, ++i) ! 183: ; ! 184: } ! 185: if (temp != 1) { ! 186: as_warn("Alignment not a power of 2"); ! 187: } ! 188: temp = i; ! 189: if (*input_line_pointer == ',') { ! 190: input_line_pointer ++; ! 191: temp_fill = get_absolute_expression (); ! 192: } else { ! 193: if ( frchain_now->frch_nsect == text_nsect ) ! 194: temp_fill = OP_NOP; ! 195: else ! 196: temp_fill = 0; ! 197: } ! 198: if ( frchain_now->frch_nsect == text_nsect ) /* emit NOPs! */ ! 199: { /* Grow the code frag as needed and dump nops into it. */ ! 200: if ( bytes & 3 ) ! 201: as_warn( "Instruction alignment must be a multiple of 4." ); ! 202: bytes &= ~3; ! 203: /* This is really tacky, but works for a fixed width insn machine */ ! 204: while ( bytes && ((insn_count * 4) % bytes) != 0 ) ! 205: { ! 206: toP = frag_more(4); /* Add an instruction */ ! 207: /* put out the opcode */ ! 208: md_insn_to_chars(toP, temp_fill, 4); /* Fill instruction */ ! 209: insn_count++; ! 210: } ! 211: /* Clean up */ ! 212: demand_empty_rest_of_line(); ! 213: return; ! 214: } ! 215: /* Only make a frag if we HAVE to. . . */ ! 216: if (temp) { ! 217: frag_align (temp, (int)temp_fill); ! 218: } ! 219: /* ! 220: * If this alignment is larger than any previous alignment then this ! 221: * becomes the section's alignment. ! 222: */ ! 223: if(frchain_now->frch_section.align < temp) ! 224: frchain_now->frch_section.align = temp; ! 225: demand_empty_rest_of_line(); ! 226: return; ! 227: } ! 228: ! 229: static ! 230: void ! 231: s_i860_org( ! 232: int value) ! 233: { ! 234: register segT segment; ! 235: expressionS exp; ! 236: register long int temp_fill; ! 237: register char *p; ! 238: extern segT get_known_segmented_expression(); ! 239: ! 240: /* ! 241: * Don't believe the documentation of BSD 4.2 AS. ! 242: * There is no such thing as a sub-segment-relative origin. ! 243: * Any absolute origin is given a warning, then assumed to be segment-relative. ! 244: * Any segmented origin expression ("foo+42") had better be in the right ! 245: * segment or the .org is ignored. ! 246: * ! 247: * BSD 4.2 AS warns if you try to .org backwards. We cannot because we ! 248: * never know sub-segment sizes when we are reading code. ! 249: * BSD will crash trying to emit -ve numbers of filler bytes in certain ! 250: * .orgs. We don't crash, but see as-write for that code. ! 251: */ ! 252: segment = get_known_segmented_expression(& exp); ! 253: if ( *input_line_pointer == ',' ) { ! 254: input_line_pointer ++; ! 255: temp_fill = get_absolute_expression (); ! 256: } else ! 257: temp_fill = 0; ! 258: ! 259: if((segment != SEG_SECT || ! 260: exp.X_add_symbol->sy_other != frchain_now->frch_nsect) && ! 261: segment != SEG_ABSOLUTE) ! 262: as_warn("Illegal expression. current section assumed."); ! 263: ! 264: if ( exp.X_add_symbol != NULL ) ! 265: as_warn("Symbol relative .org may corrupt alignment."); ! 266: else if ( exp.X_add_number & 3 ) ! 267: { ! 268: exp.X_add_number &= ~3; ! 269: as_warn(".org not on instruction boundry. Adjusted to \".org %ld\"", ! 270: exp.X_add_number); ! 271: } ! 272: if ( exp.X_add_symbol == NULL ) ! 273: insn_count = exp.X_add_number >> 2; ! 274: p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol, ! 275: exp . X_add_number, (char *)0); ! 276: * p = temp_fill; ! 277: ! 278: demand_empty_rest_of_line(); ! 279: } ! 280: ! 281: ! 282: /* ! 283: * This function is called once, at assembler startup time. This should ! 284: * set up all the tables, etc that the MD part of the assembler needs ! 285: */ ! 286: void ! 287: md_begin( ! 288: void) ! 289: { ! 290: register char *retval = NULL; ! 291: register int i; ! 292: int j = 0; ! 293: ! 294: insn_count = 0; ! 295: if ((op_hash = hash_new()) == NULL) ! 296: as_fatal("Virtual memory exhausted"); ! 297: ! 298: for (i = 0; i < NUMOPCODES; ++i) { ! 299: if (~i860_opcodes[i].mask & i860_opcodes[i].match) { ! 300: printf("bad opcode - `%s %s'\n", ! 301: i860_opcodes[i].name, i860_opcodes[i].args); ! 302: ++j; ! 303: } ! 304: } ! 305: ! 306: if (j) ! 307: exit(1); ! 308: ! 309: for (i = 0; i < NUMOPCODES; ++i) { ! 310: retval = hash_insert(op_hash, (char *)i860_opcodes[i].name, ! 311: (char *)&i860_opcodes[i]); ! 312: if(retval && *retval) { ! 313: as_fatal("Internal Error: Can't hash %s: %s", ! 314: i860_opcodes[i].name, retval); ! 315: } ! 316: while (!i860_opcodes[i].last) ! 317: ++i; ! 318: } ! 319: for (i = '0'; i < '8'; ++i) ! 320: octal[i] = 1; ! 321: for (i = '0'; i <= '9'; ++i) ! 322: toHex[i] = i - '0'; ! 323: for (i = 'a'; i <= 'f'; ++i) ! 324: toHex[i] = i + 10 - 'a'; ! 325: for (i = 'A'; i <= 'F'; ++i) ! 326: toHex[i] = i + 10 - 'A'; ! 327: ! 328: I860_errors = 0; ! 329: return; ! 330: } ! 331: ! 332: void ! 333: md_end( ! 334: void) ! 335: { ! 336: if ( I860_errors ) ! 337: { ! 338: fprintf( stderr, "%d fatal %s encountered during assembly.\n", I860_errors, ! 339: (I860_errors == 1 ? "error" : "errors") ); ! 340: exit( 42 ); /* Fatal errors seen during assembly */ ! 341: } ! 342: ! 343: return; ! 344: } ! 345: ! 346: void ! 347: md_assemble( ! 348: char *str) ! 349: { ! 350: char *toP; ! 351: int flags; ! 352: ! 353: assert(str); ! 354: flags = i860_ip(str); ! 355: if ( flags & INSERT_NOP ) ! 356: { ! 357: toP = frag_more(4); ! 358: /* put out the opcode */ ! 359: md_insn_to_chars(toP, OP_NOP, 4); ! 360: ++insn_count; ! 361: } ! 362: toP = frag_more(4); ! 363: /* put out the opcode */ ! 364: md_insn_to_chars(toP, the_insn.opcode, 4); ! 365: ++insn_count; ! 366: ! 367: /* put out the symbol-dependent stuff */ ! 368: if (the_insn.reloc != NO_RELOC) { ! 369: fix_new( ! 370: frag_now, /* which frag */ ! 371: (toP - frag_now->fr_literal), /* where */ ! 372: 4, /* size */ ! 373: the_insn.exp.X_add_symbol, ! 374: the_insn.exp.X_subtract_symbol, ! 375: the_insn.exp.X_add_number, ! 376: the_insn.pcrel, 0, ! 377: the_insn.reloc ! 378: ); ! 379: } ! 380: } ! 381: ! 382: static ! 383: int ! 384: i860_ip( ! 385: char *str) ! 386: { ! 387: char *s; ! 388: char *op; ! 389: const char *args; ! 390: char c; ! 391: struct i860_opcode *insn; ! 392: char *argsStart; ! 393: char *s1; ! 394: unsigned long opcode; ! 395: unsigned int mask; ! 396: int this_insn_is_dual = 0; ! 397: int adjustment; ! 398: int align_mask; ! 399: int match = FALSE; ! 400: int comma = 0; ! 401: int flags = 0; ! 402: static int expect_int_insn; /* Tracking for fp/int insns in dual mode. */ ! 403: ! 404: /* Advance s to end of opcode */ ! 405: for (s = str; islower(*s) || *s == '.' || isdigit(*s); ++s) ! 406: ; ! 407: switch (*s) { ! 408: ! 409: case '\0': ! 410: break; ! 411: ! 412: case ',': ! 413: comma = 1; ! 414: ! 415: /*FALLTHROUGH*/ ! 416: ! 417: case ' ': ! 418: case '\t': ! 419: *s++ = '\0'; ! 420: break; ! 421: ! 422: default: ! 423: as_warn("Unknown opcode: `%s'", str); ! 424: exit(1); ! 425: } ! 426: /* Code to sniff for 'd.' prefix here and flag for dual insn mode */ ! 427: op = str; ! 428: if ( *op == 'd' && *(op + 1) == '.' ) ! 429: { ! 430: op += 2; ! 431: this_insn_is_dual = 1; ! 432: } ! 433: ! 434: if ((insn = (struct i860_opcode *) hash_find(op_hash, op)) == NULL) { ! 435: as_warn("Unknown instruction or format: `%s'.", str); ! 436: memset(&the_insn, '\0', sizeof(the_insn)); /* Patch in no-op to hold alignment */ ! 437: the_insn.reloc = NO_RELOC; ! 438: the_insn.opcode = OP_NOP; ! 439: ++I860_errors; /* Flag as fatal error */ ! 440: return flags; ! 441: } ! 442: if (comma) { ! 443: *--s = ','; ! 444: } ! 445: argsStart = s; ! 446: for (;;) { ! 447: opcode = insn->match; ! 448: memset(&the_insn, '\0', sizeof(the_insn)); ! 449: the_insn.reloc = NO_RELOC; ! 450: ! 451: /* ! 452: * Build the opcode, checking as we go to make ! 453: * sure that the operands match ! 454: */ ! 455: for (args = insn->args; ; ++args) { ! 456: align_mask = 0; ! 457: switch (*args) { ! 458: ! 459: case '\0': /* end of args */ ! 460: if (*s == '\0') { ! 461: match = TRUE; ! 462: } ! 463: break; ! 464: ! 465: case '+': ! 466: case '(': /* these must match exactly */ ! 467: case ')': ! 468: case ',': ! 469: case ' ': ! 470: if (*s++ == *args) ! 471: continue; ! 472: break; ! 473: ! 474: case 'C': /* Control register */ ! 475: if (strncmp(s, "fir", 3) == 0) { ! 476: s += 3; ! 477: SET_RS2(opcode, 0); ! 478: continue; ! 479: } ! 480: if (strncmp(s, "psr", 3) == 0) { ! 481: s += 3; ! 482: SET_RS2(opcode, 1); ! 483: continue; ! 484: } ! 485: if (strncmp(s, "dirbase", 7) == 0) { ! 486: s += 7; ! 487: SET_RS2(opcode, 2); ! 488: continue; ! 489: } ! 490: if (strncmp(s, "db", 2) == 0) { ! 491: s += 2; ! 492: SET_RS2(opcode, 3); ! 493: continue; ! 494: } ! 495: if (strncmp(s, "fsr", 3) == 0) { ! 496: s += 3; ! 497: SET_RS2(opcode, 4); ! 498: continue; ! 499: } ! 500: if (strncmp(s, "epsr", 4) == 0) { ! 501: s += 4; ! 502: SET_RS2(opcode, 5); ! 503: continue; ! 504: } ! 505: break; ! 506: ! 507: case '1': /* next operand must be a register */ ! 508: case '2': ! 509: case 'd': ! 510: { ! 511: switch (c = *s++) { ! 512: ! 513: case 'f': /* frame pointer */ ! 514: if (*s++ == 'p') { ! 515: mask = 3; /* register fp is alias for r3 */ ! 516: break; ! 517: } ! 518: goto error; ! 519: ! 520: case 's': /* global register */ ! 521: if (*s++ == 'p') { ! 522: mask = 2; /* register sp is alias for r2 */ ! 523: break; ! 524: } ! 525: goto error; ! 526: ! 527: case 'r': /* any register */ ! 528: if (!isdigit(c = *s++)) { ! 529: goto error; ! 530: } ! 531: if (isdigit(*s)) { ! 532: if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) { ! 533: goto error; ! 534: } ! 535: } else { ! 536: c -= '0'; ! 537: } ! 538: mask= c; ! 539: break; ! 540: ! 541: default: ! 542: goto error; ! 543: } ! 544: /* ! 545: * Got the register, now figure out where ! 546: * it goes in the opcode. ! 547: */ ! 548: switch (*args) { ! 549: ! 550: case '1': ! 551: SET_RS1(opcode, mask); ! 552: continue; ! 553: ! 554: case '2': ! 555: SET_RS2(opcode, mask); ! 556: continue; ! 557: ! 558: case 'd': ! 559: SET_RD(opcode, mask); ! 560: continue; ! 561: } ! 562: } ! 563: break; ! 564: ! 565: case 'e': /* next operand is a floating point register */ ! 566: case 'f': ! 567: case 'g': ! 568: case 'E': ! 569: case 'F': ! 570: case 'G': ! 571: case 'H': ! 572: if (*s++ == 'f' && isdigit(*s)) { ! 573: mask = *s++; ! 574: if (isdigit(*s)) { ! 575: mask = 10 * (mask - '0') + (*s++ - '0'); ! 576: if (mask >= 32) { ! 577: break; ! 578: } ! 579: } else { ! 580: mask -= '0'; ! 581: } ! 582: if ( (*args == 'E' || *args == 'F' || *args == 'G') && (mask & 1) ) ! 583: { ! 584: as_warn( "f%d: Even register required. Adjusted to f%d.", ! 585: mask, mask & 0x1E ); ! 586: mask &= 0x1E; ! 587: } ! 588: else if ( *args == 'H' && (mask & 3) ) ! 589: { ! 590: as_warn( "f%d: Quad register required. Adjusted to f%d.", ! 591: mask, mask & 0x1C ); ! 592: mask &= 0x1C; ! 593: } ! 594: switch (*args) { ! 595: ! 596: case 'e': ! 597: case 'E': ! 598: SET_RS1(opcode, mask); ! 599: continue; ! 600: ! 601: case 'f': ! 602: case 'F': ! 603: SET_RS2(opcode, mask); ! 604: continue; ! 605: ! 606: case 'g': ! 607: case 'G': ! 608: case 'H': ! 609: SET_RD(opcode, mask); ! 610: continue; ! 611: } ! 612: } ! 613: break; ! 614: ! 615: case 'B': /* 5 bit immediate unsigned constant */ ! 616: (void)getExpression(s); ! 617: s = expr_end; ! 618: if ( the_insn.exp.X_seg != SEG_ABSOLUTE ) ! 619: { ! 620: as_warn( "Constant expression expected" ); ! 621: ++I860_errors; ! 622: } ! 623: if ( the_insn.exp.X_add_number < 0 || the_insn.exp.X_add_number > 31 ) ! 624: as_warn( "Constant must be between 0 and 31. Modulo 32 applied." ); ! 625: SET_RS1(opcode, the_insn.exp.X_add_number); /* Takes const modulo 32 */ ! 626: continue; ! 627: ! 628: case 'D': /* immediate unsigned constant used in shift opcodes */ ! 629: (void)getExpression(s); ! 630: s = expr_end; ! 631: if ( the_insn.exp.X_seg != SEG_ABSOLUTE ) ! 632: { ! 633: as_warn( "Constant expression expected" ); ! 634: ++I860_errors; ! 635: } ! 636: if ( the_insn.exp.X_add_number < 0 || the_insn.exp.X_add_number > 31 ) ! 637: as_warn( "Constant must be between 0 and 31. Modulo 32 applied." ); ! 638: opcode |= (the_insn.exp.X_add_number & 0x1F); ! 639: continue; ! 640: ! 641: case 'i': /* low 16 bits, byte aligned */ ! 642: the_insn.reloc = I860_RELOC_LOW0; ! 643: goto immediate; ! 644: ! 645: case 'I': /* high 16 bits */ ! 646: the_insn.reloc = I860_RELOC_HIGH; ! 647: goto immediate; ! 648: ! 649: case 'j': /* low 16 bits, short aligned */ ! 650: the_insn.reloc = I860_RELOC_LOW1; ! 651: align_mask = 1; ! 652: goto immediate; ! 653: ! 654: case 'k': /* low 16 bits, int aligned */ ! 655: the_insn.reloc = I860_RELOC_LOW2; ! 656: align_mask = 3; ! 657: goto immediate; ! 658: ! 659: case 'l': /* low 16 bits, double aligned */ ! 660: the_insn.reloc = I860_RELOC_LOW3; ! 661: align_mask = 7; ! 662: goto immediate; ! 663: ! 664: case 'm': /* low 16 bits, quad aligned */ ! 665: the_insn.reloc = I860_RELOC_LOW4; ! 666: align_mask = 15; ! 667: goto immediate; ! 668: ! 669: case 'n': /* low 16 bits, byte aligned, split field */ ! 670: the_insn.reloc = I860_RELOC_SPLIT0; ! 671: goto immediate; ! 672: ! 673: case 'o': /* low 16 bits, short aligned, split field */ ! 674: the_insn.reloc = I860_RELOC_SPLIT1; ! 675: align_mask = 1; ! 676: goto immediate; ! 677: ! 678: case 'p': /* low 16 bits, int aligned, split field */ ! 679: the_insn.reloc = I860_RELOC_SPLIT2; ! 680: align_mask = 3; ! 681: goto immediate; ! 682: ! 683: case 'J': /* High 16 bits, requiring adjustment */ ! 684: the_insn.reloc = I860_RELOC_HIGHADJ; ! 685: goto immediate; ! 686: ! 687: ! 688: case 'K': /* 26 bit PC relative immediate */ ! 689: the_insn.reloc = I860_RELOC_BRADDR; ! 690: the_insn.pcrel = 1; ! 691: goto immediate; ! 692: ! 693: case 'L': /* 16 bit PC relative split format immediate */ ! 694: the_insn.reloc = I860_RELOC_SPLIT0; ! 695: the_insn.pcrel = 1; ! 696: goto immediate; ! 697: /*FALLTHROUGH*/ ! 698: ! 699: immediate: ! 700: if(*s==' ') ! 701: s++; ! 702: adjustment = 0; ! 703: if ( *s == 'h' && *(s + 1) == '%' ) ! 704: { ! 705: adjustment = I860_RELOC_HIGH; ! 706: if ( the_insn.reloc == I860_RELOC_LOW0 && the_insn.pcrel == 0 ) ! 707: { ! 708: the_insn.reloc = I860_RELOC_HIGH; ! 709: } ! 710: else ! 711: as_warn("Improper use of h%%."); ! 712: s += 2; ! 713: } ! 714: else if ( *s == 'h' && *(s + 1) == 'a' && *(s + 2) == '%' ) ! 715: { ! 716: adjustment = I860_RELOC_HIGHADJ; ! 717: if ( the_insn.reloc == I860_RELOC_LOW0 && the_insn.pcrel == 0 ) ! 718: { ! 719: the_insn.reloc = I860_RELOC_HIGHADJ; ! 720: } ! 721: else ! 722: as_warn("Improper use of ha%%."); ! 723: ! 724: s += 3; ! 725: } ! 726: else if ( *s == 'l' && *(s + 1) == '%' ) ! 727: { /* the_insn.reloc is correct as is. */ ! 728: adjustment = I860_RELOC_LOW0; ! 729: s += 2; ! 730: } ! 731: /* Note that if the getExpression() fails, we will still have ! 732: created U entries in the symbol table for the 'symbols' ! 733: in the input string. Try not to create U symbols for ! 734: registers, etc. */ ! 735: ! 736: /* This stuff checks to see if the expression ends ! 737: in '(', as in ld.l foo(r20). If it does, it ! 738: removes the '(' from the expression, and ! 739: re-sets 's' to point to the right place */ ! 740: ! 741: for(s1=s;*s1 && *s1!=','&& *s1!=')';s1++) ! 742: ; ! 743: ! 744: if( s1 != s && *s1 == '(' && s1[1] == 'r' && isdigit(s1[2]) ! 745: && (s1[3]==')' || (isdigit(s1[3]) && s1[4] == ')')) ) { ! 746: *s1='\0'; ! 747: (void)getExpression(s); ! 748: *s1='('; ! 749: s=s1; ! 750: } ! 751: else ! 752: { ! 753: (void)getExpression(s); ! 754: s = expr_end; ! 755: } ! 756: /* ! 757: * If there is an adjustment, we assume the user knows what ! 758: * they are doing. If no adjustment, we very carefully range ! 759: * check for both signed and unsigned operations, to avoid ! 760: * unpleasant suprises. The checks are skipped for branch and ! 761: * call instructions, matching the behavior of the Intel assembler. ! 762: */ ! 763: if ( ! adjustment && *op != 'b' && *op != 'c' ) ! 764: { ! 765: if ( the_insn.exp.X_seg != SEG_ABSOLUTE ) ! 766: { ! 767: as_warn( ! 768: "Non-absolute expression requires h%%, l%%, or ha%% prefix." ! 769: ); ! 770: } ! 771: else ! 772: { ! 773: if ( IS_LOGOP(opcode) ) ! 774: { ! 775: if ( ((unsigned)the_insn.exp.X_add_number) > 0xFFFF ) ! 776: as_warn("%lu is too big for 16 bit unsigned value!", ! 777: the_insn.exp.X_add_number); ! 778: } ! 779: else ! 780: { ! 781: if ( ((int)the_insn.exp.X_add_number) > 32767 || ! 782: ((int)the_insn.exp.X_add_number) < -32768 ) ! 783: as_warn("%ld is out of range for 16 bit signed value!", ! 784: the_insn.exp.X_add_number); ! 785: ! 786: if ((align_mask & the_insn.exp.X_add_number) != 0) ! 787: as_warn("Const offset 0x%x incorrectly aligned.", ! 788: (unsigned int)the_insn.exp.X_add_number); ! 789: } ! 790: } ! 791: } ! 792: continue; ! 793: ! 794: default: ! 795: abort(); ! 796: } ! 797: break; ! 798: } ! 799: error: ! 800: if (match == FALSE) { ! 801: /* args don't match */ ! 802: if (!insn->last) { ! 803: ++insn; ! 804: s = argsStart; ! 805: continue; ! 806: } else { ! 807: as_warn("Illegal operands (%s %s).", str, argsStart); ! 808: ++I860_errors; ! 809: return flags; ! 810: } ! 811: } ! 812: break; ! 813: } ! 814: /* If the last insn was dual, check and make sure that this insn is integer insn */ ! 815: if ( expect_int_insn && (dual_insn_mode || this_insn_is_dual) ) ! 816: { ! 817: if ( (opcode & OP_PREFIX_MASK) == PREFIX_FPU || opcode == OP_FNOP ) ! 818: { ! 819: as_warn( "Core half of prev dual insn pair missing." ); ! 820: } ! 821: expect_int_insn = 0; ! 822: } ! 823: /* Check the insn format and fold in the dual mode bit if appropriate. */ ! 824: if ( dual_insn_mode || this_insn_is_dual ) ! 825: { ! 826: if ( (opcode & OP_PREFIX_MASK) == PREFIX_FPU || opcode == OP_FNOP ) ! 827: { ! 828: if ( insn_count & 1 ) /* Odd insn, not on 64 bit bound! */ ! 829: { ! 830: as_warn( "Dual FP insn on odd addr." ); ! 831: } ! 832: opcode |= DUAL_INSN_MODE_BIT; ! 833: expect_int_insn = 1; ! 834: } ! 835: else if ( this_insn_is_dual ) /* d. prefix on a non-FPU insn error */ ! 836: { ! 837: as_warn("d. prefix not allowed for `%s'. (Ignored!)", op); ! 838: } ! 839: } ! 840: else ! 841: expect_int_insn = 0; /* Single insn mode. */ ! 842: /* Check for correct alignment of const in branch to label + offset */ ! 843: if ( (the_insn.reloc == I860_RELOC_BRADDR ! 844: || (the_insn.pcrel && the_insn.reloc == I860_RELOC_SPLIT0) ! 845: ) && (the_insn.exp.X_add_number & 3) ) ! 846: as_warn( "Branch offset is not aligned to instruction boundry!" ); ! 847: the_insn.opcode = opcode; ! 848: return flags; ! 849: } ! 850: ! 851: static ! 852: int ! 853: getExpression( ! 854: char *str) ! 855: { ! 856: char *save_in; ! 857: segT seg; ! 858: ! 859: save_in = input_line_pointer; ! 860: input_line_pointer = str; ! 861: switch (seg = expression(&the_insn.exp)) { ! 862: ! 863: case SEG_ABSOLUTE: ! 864: case SEG_SECT: ! 865: case SEG_DIFFSECT: ! 866: case SEG_UNKNOWN: ! 867: case SEG_BIG: ! 868: case SEG_NONE: ! 869: break; ! 870: ! 871: default: ! 872: the_insn.error = "bad segment"; ! 873: expr_end = input_line_pointer; ! 874: input_line_pointer=save_in; ! 875: return 1; ! 876: } ! 877: expr_end = input_line_pointer; ! 878: input_line_pointer = save_in; ! 879: return 0; ! 880: } ! 881: ! 882: ! 883: #define MAX_LITTLENUMS 6 ! 884: ! 885: /* ! 886: This is identical to the md_atof in m68k.c. I think this is right, ! 887: but I'm not sure. ! 888: ! 889: Turn a string in input_line_pointer into a floating point constant of type ! 890: type, and store the appropriate bytes in *litP. The number of LITTLENUMS ! 891: emitted is stored in *sizeP . An error message is returned, or NULL on OK. ! 892: */ ! 893: char * ! 894: md_atof( ! 895: int type, ! 896: char *litP, ! 897: int *sizeP) ! 898: { ! 899: int prec; ! 900: LITTLENUM_TYPE words[MAX_LITTLENUMS]; ! 901: LITTLENUM_TYPE *wordP; ! 902: char *t; ! 903: char *atof_ieee(); ! 904: ! 905: switch(type) { ! 906: ! 907: case 'f': ! 908: case 'F': ! 909: case 's': ! 910: case 'S': ! 911: prec = 2; ! 912: break; ! 913: ! 914: case 'd': ! 915: case 'D': ! 916: case 'r': ! 917: case 'R': ! 918: prec = 4; ! 919: break; ! 920: /* The following two formats get reduced to doubles. */ ! 921: case 'x': ! 922: case 'X': ! 923: type = 'd'; ! 924: prec = 4; ! 925: break; ! 926: ! 927: case 'p': ! 928: case 'P': ! 929: type = 'd'; ! 930: prec = 4; ! 931: break; ! 932: ! 933: default: ! 934: *sizeP=0; ! 935: return "Bad call to MD_ATOF()"; ! 936: } ! 937: t=atof_ieee(input_line_pointer,type,words); ! 938: if(t) ! 939: input_line_pointer=t; ! 940: *sizeP=prec * sizeof(LITTLENUM_TYPE); ! 941: for(wordP=words;prec--;) { ! 942: md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); ! 943: litP+=sizeof(LITTLENUM_TYPE); ! 944: } ! 945: return ""; /* Someone should teach Dean about null pointers */ ! 946: } ! 947: ! 948: /* ! 949: * Write out big-endian. Valid for data only in our I860 implementation. ! 950: */ ! 951: void ! 952: md_number_to_chars( ! 953: char *buf, ! 954: long val, ! 955: int n) ! 956: { ! 957: ! 958: switch(n) { ! 959: ! 960: case 4: ! 961: *buf++ = val >> 24; ! 962: *buf++ = val >> 16; ! 963: case 2: ! 964: *buf++ = val >> 8; ! 965: case 1: ! 966: *buf = val; ! 967: break; ! 968: ! 969: default: ! 970: abort(); ! 971: } ! 972: return; ! 973: } ! 974: ! 975: #ifdef BYTE_SWAP ! 976: /* ! 977: * Write out little-endian. Valid for instructions only in ! 978: * our i860 implementation. ! 979: */ ! 980: static ! 981: void ! 982: md_insn_to_chars( ! 983: unsigned char *buf, ! 984: long val, ! 985: int n) ! 986: { ! 987: ! 988: switch(n) { ! 989: ! 990: case 4: ! 991: *buf++ = val; ! 992: *buf++ = val >> 8; ! 993: *buf++ = val >> 16; ! 994: *buf++ = val >> 24; ! 995: break; ! 996: case 2: ! 997: *buf++ = val; ! 998: *buf++ = val >> 8; ! 999: break; ! 1000: case 1: ! 1001: *buf = val; ! 1002: break; ! 1003: ! 1004: default: ! 1005: abort(); ! 1006: } ! 1007: return; ! 1008: } ! 1009: #else /* !defined(BYTE_SWAP) */ ! 1010: ! 1011: static ! 1012: void ! 1013: md_insn_to_chars( ! 1014: unsigned char *buf, ! 1015: long val, ! 1016: int n) ! 1017: { ! 1018: md_number_to_chars(buf,val,n); ! 1019: } ! 1020: #endif /* BYTE_SWAP */ ! 1021: ! 1022: void ! 1023: md_number_to_imm( ! 1024: unsigned char *buf, ! 1025: long val, ! 1026: int n, ! 1027: fixS *fixP, ! 1028: int nsect) ! 1029: { ! 1030: unsigned long opcode; ! 1031: ! 1032: if ( nsect == text_nsect && (n % 4) != 0 ) ! 1033: as_warn("Immediate write of non-aligned data into text segment." ); ! 1034: ! 1035: if (nsect != text_nsect || ! 1036: fixP->fx_r_type == NO_RELOC || ! 1037: fixP->fx_r_type == I860_RELOC_VANILLA) ! 1038: { ! 1039: switch (n) { /* Write out the data big-endian style. */ ! 1040: case 1: ! 1041: *buf = val; ! 1042: break; ! 1043: case 2: ! 1044: *buf++ = (val>>8); ! 1045: *buf = val; ! 1046: break; ! 1047: case 4: ! 1048: *buf++ = (val>>24); ! 1049: *buf++ = (val>>16); ! 1050: *buf++ = (val>>8); ! 1051: *buf = val; ! 1052: break; ! 1053: default: ! 1054: abort(); ! 1055: } ! 1056: return; ! 1057: } ! 1058: ! 1059: assert(n == 4); /* Better be an instruction with relocation data.... */ ! 1060: assert(fixP->fx_r_type < NO_RELOC && fixP->fx_r_type > I860_RELOC_VANILLA); ! 1061: /* ! 1062: * Here is where we do initial bit fiddling to load immediate ! 1063: * values into the i860 bit fields. ! 1064: */ ! 1065: #ifdef BYTE_SWAP ! 1066: /* Note that all of these insns are ultimately little-endian */ ! 1067: /* Get the opcode from the buffer. Less efficient, but more coherent... */ ! 1068: opcode = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; ! 1069: #else ! 1070: opcode = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; ! 1071: #endif ! 1072: /* Apply the relocation value 'val' */ ! 1073: switch (fixP->fx_r_type) { ! 1074: case I860_RELOC_PAIR: ! 1075: as_warn("questionable relocation type I860_RELOC_PAIR"); ! 1076: break; ! 1077: case I860_RELOC_HIGH: ! 1078: opcode &= ~0xFFFF; ! 1079: opcode |= ((val >> 16) & 0xFFFF); ! 1080: break; ! 1081: case I860_RELOC_LOW0: ! 1082: opcode &= ~0xFFFF; ! 1083: opcode |= (val & 0xFFFF); ! 1084: break; ! 1085: case I860_RELOC_LOW1: ! 1086: opcode &= 0xFFFF0001; ! 1087: opcode |= (val & 0xFFFE); /* Bit 0 is an insn bit! */ ! 1088: break; ! 1089: case I860_RELOC_LOW2: ! 1090: opcode &= 0xFFFF0003; ! 1091: opcode |= (val & 0xFFFC); /* Bits 0 and 1 are insn bits! */ ! 1092: break; ! 1093: case I860_RELOC_LOW3: ! 1094: opcode &= 0xFFFF0007; ! 1095: opcode |= (val & 0xFFF8); /* Bits 0 thru 2 are insn bits! */ ! 1096: break; ! 1097: case I860_RELOC_LOW4: ! 1098: opcode &= 0xFFFF000F; ! 1099: opcode |= (val & 0xFFF0); /* Bits 0 thru 3 are insn bits! */ ! 1100: break; ! 1101: case I860_RELOC_SPLIT0: ! 1102: opcode &= 0xFFE0F800; ! 1103: if ( fixP->fx_pcrel ) /* A 16 bit branch relative insn? */ ! 1104: val >>= 2; /* Convert to word address */ ! 1105: opcode |= ((val & 0xF800) << 5) | (val & 0x7FF); ! 1106: break; ! 1107: case I860_RELOC_SPLIT1: ! 1108: opcode &= 0xFFE0F801; /* Again, bit 0 is an insn bit! */ ! 1109: opcode |= ((val & 0xF800) << 5) | (val & 0x7FE); ! 1110: break; ! 1111: case I860_RELOC_SPLIT2: ! 1112: opcode &= 0xFFE0F803; /* Bits 0 and 1 are insn bits! */ ! 1113: opcode |= ((val & 0xF800) << 5) | (val & 0x7FC); ! 1114: break; ! 1115: case I860_RELOC_HIGHADJ: /* Adjusted variant */ ! 1116: opcode &= ~0xFFFF; ! 1117: /* If the low half would be negative, compensate by adding 1 to ! 1118: * high half. ! 1119: */ ! 1120: if ( (val & 0x8000) != 0 ) ! 1121: val = (val >> 16) + 1; ! 1122: else ! 1123: val = (val >> 16); ! 1124: opcode |= (val & 0xFFFF); ! 1125: break; ! 1126: case I860_RELOC_BRADDR: ! 1127: if ( fixP->fx_pcrel ) /* A 26 bit branch relative insn? */ ! 1128: val >>= 2; /* Convert to word address */ ! 1129: opcode &= 0xFC000000; ! 1130: opcode |= (val & 0x03FFFFFF); ! 1131: break; ! 1132: ! 1133: default: ! 1134: as_warn("bad relocation type: 0x%02x", fixP->fx_r_type); ! 1135: break; ! 1136: } ! 1137: #ifdef BYTE_SWAP ! 1138: buf[0] = opcode; ! 1139: buf[1] = opcode >> 8; ! 1140: buf[2] = opcode >> 16; ! 1141: buf[3] = opcode >> 24; ! 1142: #else ! 1143: buf[3] = opcode; ! 1144: buf[2] = opcode >> 8; ! 1145: buf[1] = opcode >> 16; ! 1146: buf[0] = opcode >> 24; ! 1147: #endif ! 1148: return; ! 1149: } ! 1150: ! 1151: /* should never be called for i860 */ ! 1152: void ! 1153: md_convert_frag( ! 1154: fragS *fragP) ! 1155: { ! 1156: fprintf(stderr, "i860_convert_frag\n"); ! 1157: abort(); ! 1158: } ! 1159: ! 1160: /* should never be called for i860 */ ! 1161: int ! 1162: md_estimate_size_before_relax( ! 1163: fragS *fragP, ! 1164: int nsect) ! 1165: { ! 1166: fprintf(stderr, "i860_estimate_size_before_relax\n"); ! 1167: abort(); ! 1168: return 0; ! 1169: } ! 1170: ! 1171: #ifdef I860_DEBUG ! 1172: /* for debugging only */ ! 1173: static void ! 1174: print_insn( ! 1175: struct i860_it *insn) ! 1176: { ! 1177: char *Reloc[] = { ! 1178: "RELOC_8", ! 1179: "RELOC_16", ! 1180: "RELOC_32", ! 1181: "RELOC_DISP8", ! 1182: "RELOC_DISP16", ! 1183: "RELOC_DISP32", ! 1184: "RELOC_WDISP30", ! 1185: "RELOC_WDISP22", ! 1186: "RELOC_HI22", ! 1187: "RELOC_22", ! 1188: "RELOC_13", ! 1189: "RELOC_LO10", ! 1190: "RELOC_SFA_BASE", ! 1191: "RELOC_SFA_OFF13", ! 1192: "RELOC_BASE10", ! 1193: "RELOC_BASE13", ! 1194: "RELOC_BASE22", ! 1195: "RELOC_PC10", ! 1196: "RELOC_PC22", ! 1197: "RELOC_JMP_TBL", ! 1198: "RELOC_SEGOFF16", ! 1199: "RELOC_GLOB_DAT", ! 1200: "RELOC_JMP_SLOT", ! 1201: "RELOC_RELATIVE", ! 1202: "NO_RELOC" ! 1203: }; ! 1204: ! 1205: if (insn->error) { ! 1206: fprintf(stderr, "ERROR: %s\n"); ! 1207: } ! 1208: fprintf(stderr, "opcode=0x%08x\n", insn->opcode); ! 1209: fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]); ! 1210: fprintf(stderr, "exp = {\n"); ! 1211: fprintf(stderr, "\t\tX_add_symbol = %s\n", ! 1212: insn->exp.X_add_symbol ? ! 1213: (insn->exp.X_add_symbol->sy_name ? ! 1214: insn->exp.X_add_symbol->sy_name : "???") : "0"); ! 1215: fprintf(stderr, "\t\tX_sub_symbol = %s\n", ! 1216: insn->exp.X_subtract_symbol ? ! 1217: (insn->exp.X_subtract_symbol->sy_name ? ! 1218: insn->exp.X_subtract_symbol->sy_name : "???") : "0"); ! 1219: fprintf(stderr, "\t\tX_add_number = %d\n", ! 1220: insn->exp.X_add_number); ! 1221: fprintf(stderr, "}\n"); ! 1222: return; ! 1223: } ! 1224: #endif /* I860_DEBUG */ ! 1225: ! 1226: int ! 1227: md_parse_option( ! 1228: char **argP, ! 1229: int *cntP, ! 1230: char ***vecP) ! 1231: { ! 1232: return 1; ! 1233: } ! 1234:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.