1/* m88k.c -- Assemble for the 88100 2 Copyright (C) 1989 Free Software Foundation, Inc. 3 4This file is not yet part of GAS, the GNU Assembler. 5 6GAS is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 1, or (at your option) 9any later version. 10 11GAS is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GAS; see the file COPYING. If not, write to 18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 19 20#include <ctype.h> 21#include <string.h> 22#include <stdlib.h> 23#include <mach-o/m88k/reloc.h> 24#include "m88k-opcode.h" 25#include "as.h" 26#include "flonum.h" 27#include "expr.h" 28#include "hash.h" 29#include "frags.h" 30#include "fixes.h" 31#include "read.h" 32#include "md.h" 33#include "obstack.h" 34#include "symbols.h" 35#include "messages.h" 36#include "input-scrub.h" 37#include "sections.h" 38 39/* 40 * These are the default cputype and cpusubtype for the m88k architecture. 41 */ 42const cpu_type_t md_cputype = CPU_TYPE_MC88000; 43cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_MC88000_ALL; 44 45/* This is the byte sex for the m88k architecture */ 46const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX; 47 48#ifdef NeXT_MOD 49static int32_t in_delay_slot = 0; 50#endif 51 52static char *cmpslot[] = { "**", "**", "eq", "ne", "gt", "le", "lt", "ge", 53 "hi", "ls", "lo", "hs", 54#ifdef m88110 55 "be", "nb", "he", "nh", 56#endif /* m88110 */ 57 NULL }; 58 59static struct { 60 char *name; 61 unsigned int num; 62 63} cndmsk[] = { 64 { "eq0", 0x02}, 65 { "ne0", 0x0d}, 66 { "gt0", 0x01}, 67 { "lt0", 0x0c}, 68 { "ge0", 0x03}, 69 { "le0", 0x0e}, 70 { NULL, 0x00}, 71 }; 72 73struct m88k_insn { 74 uint32_t opcode; 75 expressionS exp; 76#ifdef NeXT_MOD 77 int reloc; 78#else 79 enum reloc_type reloc; 80#endif 81}; 82 83static struct hash_control *op_hash = NULL; 84 85/* These chars start a comment anywhere in a source file (except inside 86 another comment */ 87const char md_comment_chars[] = ";"; 88 89/* These chars only start a comment at the beginning of a line. */ 90const char md_line_comment_chars[] = "#"; 91 92/* Chars that can be used to separate mant from exp in floating point nums */ 93const char md_EXP_CHARS[] = "eE"; 94 95/* Chars that mean this number is a floating point constant */ 96/* as in 0f123.456 */ 97/* or 0H1.234E-12 (see exp chars above) */ 98const char md_FLT_CHARS[] = "dDfF"; 99 100static int calcop( 101 struct m88k_opcode *format, 102 char *param, 103 struct m88k_insn *insn); 104static char * parse_reg( 105 char *param, 106 struct m88k_insn *insn, 107 struct m88k_opcode *format, 108 int parcnt); 109#ifdef m88110 110static char *parse_ereg( 111 char *param, 112 struct m88k_insn *insn, 113 struct m88k_opcode *format, 114 int parcnt); 115static char *parse_e4rot( 116 char *param, 117 struct m88k_insn *insn, 118 struct m88k_opcode *format, 119 int parcnt); 120static char *parse_xreg( 121 char *param, 122 struct m88k_insn *insn, 123 struct m88k_opcode *format, 124 int parcnt); 125#endif /* m88110 */ 126static char *parse_pcr( 127 char *param, 128 struct m88k_insn *insn, 129 struct m88k_opcode *format, 130 int parcnt); 131static char *parse_cmp( 132 char *param, 133 struct m88k_insn *insn, 134 struct m88k_opcode *format, 135 int parcnt); 136static char *parse_cnd( 137 char *param, 138 struct m88k_insn *insn, 139 struct m88k_opcode *format, 140 int parcnt); 141static char *parse_bf( 142 char *param, 143 struct m88k_insn *insn, 144 struct m88k_opcode *format, 145 int parcnt); 146static char *parse_rot( 147 char *param, 148 struct m88k_insn *insn, 149 struct m88k_opcode *format, 150 int parcnt); 151static char *parse_rsc( 152 char *param, 153 struct m88k_insn *insn, 154 struct m88k_opcode *format, 155 int parcnt); 156static char *parse_cr( 157 char *param, 158 struct m88k_insn *insn, 159 struct m88k_opcode *format, 160 int parcnt); 161static char *parse_fcr( 162 char *param, 163 struct m88k_insn *insn, 164 struct m88k_opcode *format, 165 int parcnt); 166static char *parse_cst( 167 char *param, 168 struct m88k_insn *insn, 169 struct m88k_opcode *format, 170 int parcnt); 171static char *getval( 172 char *param, 173 unsigned int *val); 174#ifdef NeXT_MOD 175static void s_reg( 176 uintptr_t reg); 177static void s_scaled( 178 uintptr_t value); 179static void s_m88k_abs( 180 uintptr_t value); 181static void s_no_delay( 182 uintptr_t value); 183static void s_dot( 184 uintptr_t value); 185#endif /* NeXT_MOD */ 186 187const pseudo_typeS md_pseudo_table[] = 188{ 189#ifdef NeXT_MOD 190 {"greg", s_reg, 'r' }, 191 {"xreg", s_reg, 'x' }, 192 {"scaled", s_scaled, 0}, 193 {"abs", s_m88k_abs, 0}, 194 {"no_delay", s_no_delay, 0}, 195 {"dot", s_dot, 0}, 196#endif 197#ifndef NeXT_MOD 198 /* At NeXT we don't allow these */ 199 {"dfloat", float_cons, 'd'}, 200 {"ffloat", float_cons, 'f'}, 201 {"global", s_globl, 0}, 202 {"half", cons, 2 }, 203 {"ln", s_line, 0}, 204 {"zero", s_space, 0}, 205 {"word", cons, 4 }, 206#endif 207 {0} 208}; 209 210#ifdef NeXT_MOD 211static 212void 213s_dot( 214uintptr_t value) 215{ 216 char *name, *end_name, delim; 217 symbolS *symbolP; 218 219 if( * input_line_pointer == '"') 220 name = input_line_pointer + 1; 221 else 222 name = input_line_pointer; 223 delim = get_symbol_end(); 224 end_name = input_line_pointer; 225 *end_name = 0; 226 227 symbolP = symbol_find_or_make (name); 228 symbolP -> sy_type = N_ABS; 229 symbolP -> sy_other = 0; /* NO_SECT */ 230 symbolP -> sy_value = obstack_next_free(&frags) - frag_now->fr_literal; 231 symbolP -> sy_frag = &zero_address_frag; 232 233 *end_name = delim; 234 totally_ignore_line(); 235} 236/* 237 * s_reg() is used to implement ".greg symbol,exp" and ".xreg symbol,exp" 238 * which set symbol to 1 or 0 depending on if the expression is a general 239 * register or extended register respectfully. These are intended for use in 240 * macros. 241 */ 242static 243void 244s_reg( 245uintptr_t reg) 246{ 247 char *name, *end_name, delim; 248 symbolS *symbolP; 249 uint32_t n_value, val; 250 251 if( * input_line_pointer == '"') 252 name = input_line_pointer + 1; 253 else 254 name = input_line_pointer; 255 delim = get_symbol_end(); 256 end_name = input_line_pointer; 257 *end_name = delim; 258 SKIP_WHITESPACE(); 259 if ( * input_line_pointer != ',' ) { 260 *end_name = 0; 261 as_warn("Expected comma after name \"%s\"", name); 262 *end_name = delim; 263 ignore_rest_of_line(); 264 return; 265 } 266 input_line_pointer ++; 267 *end_name = 0; 268 269 SKIP_WHITESPACE(); 270 n_value = 0; 271 if (*input_line_pointer == reg || *input_line_pointer == toupper(reg)){ 272 input_line_pointer++; 273 if(isdigit(*input_line_pointer)){ 274 val = 0; 275 while (isdigit(*input_line_pointer)){ 276 if ((val = val * 10 + *input_line_pointer++ - '0') > 31) 277 break; 278 } 279 SKIP_WHITESPACE(); 280 if(val <= 31 && 281 (*input_line_pointer == '\n' || *input_line_pointer == '@')) 282 n_value = 1; 283 } 284 } 285 286 symbolP = symbol_find_or_make (name); 287 symbolP -> sy_type = N_ABS; 288 symbolP -> sy_other = 0; /* NO_SECT */ 289 symbolP -> sy_value = n_value; 290 symbolP -> sy_frag = &zero_address_frag; 291 292 *end_name = delim; 293 totally_ignore_line(); 294} 295 296/* 297 * s_scaled() is used to implement ".scaled symbol,exp" which sets symbol to 1 298 * or 0 depending on if the expression is a scaled general register expression 299 * "r1[r2]" or not respectfully. This is intended for use in macros. 300 */ 301static 302void 303s_scaled( 304uintptr_t value) 305{ 306 char *name, *end_name, delim; 307 symbolS *symbolP; 308 uint32_t n_value, val; 309 310 if( * input_line_pointer == '"') 311 name = input_line_pointer + 1; 312 else 313 name = input_line_pointer; 314 delim = get_symbol_end(); 315 end_name = input_line_pointer; 316 *end_name = delim; 317 SKIP_WHITESPACE(); 318 if ( * input_line_pointer != ',' ) { 319 *end_name = 0; 320 as_warn("Expected comma after name \"%s\"", name); 321 *end_name = delim; 322 ignore_rest_of_line(); 323 return; 324 } 325 input_line_pointer ++; 326 *end_name = 0; 327 328 SKIP_WHITESPACE(); 329 n_value = 0; 330 if (*input_line_pointer == 'r' || *input_line_pointer == 'R'){ 331 input_line_pointer++; 332 if(isdigit(*input_line_pointer)){ 333 val = 0; 334 while (isdigit(*input_line_pointer)){ 335 if ((val = val * 10 + *input_line_pointer++ - '0') > 31) 336 break; 337 } 338 SKIP_WHITESPACE(); 339 if(val <= 31 && *input_line_pointer == '['){ 340 input_line_pointer++; 341 if (*input_line_pointer == 'r' || 342 *input_line_pointer == 'R'){ 343 input_line_pointer++; 344 if(isdigit(*input_line_pointer)){ 345 val = 0; 346 while (isdigit(*input_line_pointer)){ 347 if ((val = val * 10 + 348 *input_line_pointer++ - '0') > 31) 349 break; 350 } 351 if(val <= 31 && *input_line_pointer == ']'){ 352 input_line_pointer++; 353 SKIP_WHITESPACE(); 354 if(*input_line_pointer == '\n' || 355 *input_line_pointer == '@') 356 n_value = 1; 357 } 358 } 359 } 360 } 361 } 362 } 363 364 symbolP = symbol_find_or_make (name); 365 symbolP -> sy_type = N_ABS; 366 symbolP -> sy_other = 0; /* NO_SECT */ 367 symbolP -> sy_value = n_value; 368 symbolP -> sy_frag = & zero_address_frag; 369 370 *end_name = delim; 371 totally_ignore_line(); 372} 373 374/* 375 * s_m88k_abs() is used to implement ".abs symbol,exp" which sets symbol to 1 376 * or 0 depending on if the expression is an absolute expression or not 377 * respectfully. This is intended for use in macros. 378 */ 379static 380void 381s_m88k_abs( 382uintptr_t value) 383{ 384 char *name, *end_name, delim, *start; 385 symbolS *symbolP; 386 uint32_t n_value, val, is_reg_exp; 387 388 start = input_line_pointer; 389 if( * input_line_pointer == '"') 390 name = input_line_pointer + 1; 391 else 392 name = input_line_pointer; 393 delim = get_symbol_end(); 394 end_name = input_line_pointer; 395 *end_name = delim; 396 SKIP_WHITESPACE(); 397 if ( * input_line_pointer != ',' ) { 398 *end_name = 0; 399 as_warn("Expected comma after name \"%s\"", name); 400 *end_name = delim; 401 ignore_rest_of_line(); 402 return; 403 } 404 input_line_pointer ++; 405 *end_name = 0; 406 407 SKIP_WHITESPACE(); 408 is_reg_exp = 0; 409 n_value = 0; 410 if(*input_line_pointer == 'r' || *input_line_pointer == 'R'){ 411 input_line_pointer++; 412 if(isdigit(*input_line_pointer)){ 413 val = 0; 414 while (isdigit(*input_line_pointer)){ 415 if ((val = val * 10 + *input_line_pointer++ - '0') > 31) 416 break; 417 } 418 SKIP_WHITESPACE(); 419 if(val <= 31) 420 is_reg_exp = 1; 421 } 422 } 423 if(is_reg_exp == 0){ 424 *end_name = delim; 425 input_line_pointer = start; 426 s_abs(value); 427 return; 428 } 429 430 symbolP = symbol_find_or_make (name); 431 symbolP -> sy_type = N_ABS; 432 symbolP -> sy_other = 0; /* NO_SECT */ 433 symbolP -> sy_value = n_value; 434 symbolP -> sy_frag = & zero_address_frag; 435 *end_name = delim; 436 437 totally_ignore_line(); 438} 439 440/* 441 * s_no_delay() is used to implement ".no_delay string" which will abort and 442 * print the string if the last instruction assembled has a delay slot. 443 * This is intended for use in macros that expand to more than one instruction 444 * that could be put in delay slots. This is not really correct in it's 445 * operation in that it is not per-section and does not take into account 446 * anything other than assembled instructions. 447 */ 448static 449void 450s_no_delay( 451uintptr_t value) 452{ 453 char *p, c; 454 455 p = input_line_pointer; 456 while(*p != '\n' && *p != '@' && *p != '\0') 457 p++; 458 c = *p; 459 *p = '\0'; 460 461 if(in_delay_slot) 462 as_fatal("delay slot abort %s detected. Assembly stopping.", 463 input_line_pointer); 464 input_line_pointer = p; 465 *p = c; 466} 467#endif /* NeXT_MOD */ 468 469void 470md_begin( 471void) 472{ 473 const char *retval = NULL; 474 register unsigned int i = 0; 475 476 /* initialize hash table */ 477 478 op_hash = hash_new(); 479 if (op_hash == NULL) 480 as_fatal("Could not initialize hash table"); 481 482 /* loop until you see the end of the list */ 483 484 while (*m88k_opcodes[i].name) { 485 char *name = m88k_opcodes[i].name; 486 487 /* hash each mnemonic and record its position */ 488 489 retval = hash_insert(op_hash, name, (char *)&m88k_opcodes[i]); 490 491 if (retval != NULL && *retval != '\0') 492 as_fatal("Can't hash instruction '%s':%s", 493 m88k_opcodes[i].name, retval); 494 495 /* skip to next unique mnemonic or end of list */ 496 497 for (i++; !strcmp(m88k_opcodes[i].name, name); i++); 498 } 499} 500 501int 502md_parse_option( 503char **argP, 504int *cntP, 505char ***vecP) 506{ 507 return (1); 508} 509 510void 511md_assemble( 512char *op) 513{ 514 char *param, *thisfrag; 515 struct m88k_opcode *format; 516 struct m88k_insn insn; 517#ifdef NeXT_MOD 518 int32_t pcrel_reloc; 519#endif 520 521 assert(op); 522 523 /* skip over instruction to find parameters */ 524 525 /* *param != '\0' is need for instructions that have no parameters 526 like rte */ 527 for (param = op; !isspace(*param) && *param != '\0' ; param++); 528 *param++ = '\0'; 529 530 /* try to find the instruction in the hash table */ 531 532 if ((format = (struct m88k_opcode *) hash_find(op_hash, op)) == NULL) { 533 as_warn("Invalid mnemonic '%s'", op); 534 return; 535 } 536 537 /* try parsing this instruction into insn */ 538 539 while (!calcop(format,param,&insn)) 540 541 /* if it doesn't parse try the next instruction */ 542 543 if (!strcmp(format->name, format[1].name)) 544 format++; 545 else { 546 as_warn("Parameter syntax error"); 547 return; 548 } 549 550 /* grow the current frag and plop in the opcode */ 551 552 thisfrag = frag_more(4); 553 md_number_to_chars(thisfrag, insn.opcode, 4); 554#ifdef NeXT_MOD 555 in_delay_slot = format->delay_slot; 556#endif 557#ifdef NeXT_MOD /* generate stabs for debugging assembly code */ 558 /* 559 * If the -g flag is present generate a line number stab for the 560 * instruction. 561 * 562 * See the detailed comments about stabs in read_a_source_file() for a 563 * description of what is going on here. 564 */ 565 if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){ 566 (void)symbol_new( 567 "", 568 68 /* N_SLINE */, 569 text_nsect, 570 logical_input_line /* n_desc, line number */, 571 obstack_next_free(&frags) - frag_now->fr_literal, 572 frag_now); 573 } 574#endif /* NeXT_MOD */ 575 576#ifdef NeXT_MOD /* mark sections containing instructions */ 577 /* 578 * We are putting a machine instruction in this section so mark it as 579 * containg some machine instructions. 580 */ 581 frchain_now->frch_section.flags |= S_ATTR_SOME_INSTRUCTIONS; 582#endif /* NeXT_MOD */ 583 584#ifdef NeXT_MOD 585 pcrel_reloc = 0; 586 if (insn.reloc == M88K_RELOC_PC16 || insn.reloc == M88K_RELOC_PC26){ 587 /* 588 * The NeXT linker has the ability to scatter blocks of 589 * sections between labels. This requires that brances to 590 * labels that survive to the link phase must be able to 591 * be relocated. 592 */ 593 if(insn.exp.X_add_symbol != NULL && 594 (insn.exp.X_add_symbol->sy_name[0] != 'L' || flagseen ['L'])) 595 pcrel_reloc = 1; 596 else 597 pcrel_reloc = 0; 598 } 599#endif /* NeXT_MOD */ 600 601 /* if this instruction requires labels mark it for later */ 602 switch (insn.reloc) { 603 case M88K_RELOC_LO16: 604 case M88K_RELOC_HI16: 605 fix_new( 606 frag_now, 607#ifdef NeXT_MOD 608 thisfrag - frag_now->fr_literal, 609 4, 610#else 611 thisfrag - frag_now->fr_literal + 2, 612 2, 613#endif 614 insn.exp.X_add_symbol, 615 insn.exp.X_subtract_symbol, 616 insn.exp.X_add_number, 617 0, 0, 618 insn.reloc 619 ); 620 break; 621 622#ifndef NeXT_MOD 623 case M88K_RELOC_IW16: 624 fix_new( 625 frag_now, 626 thisfrag - frag_now->fr_literal, 627 4, 628 insn.exp.X_add_symbol, 629 insn.exp.X_subtract_symbol, 630 insn.exp.X_add_number, 631 0, 0, 632 insn.reloc 633 ); 634 break; 635#endif /* !defined(NeXT_MOD) */ 636 637 case M88K_RELOC_PC16: 638 fix_new( 639 frag_now, 640#ifdef NeXT_MOD 641 thisfrag - frag_now->fr_literal, 642 4, 643#else 644 thisfrag - frag_now->fr_literal + 2, 645 2, 646#endif 647 insn.exp.X_add_symbol, 648 insn.exp.X_subtract_symbol, 649 insn.exp.X_add_number, 650 1, pcrel_reloc, 651 insn.reloc 652 ); 653 break; 654 655 case M88K_RELOC_PC26: 656 fix_new( 657 frag_now, 658 thisfrag - frag_now->fr_literal, 659 4, 660 insn.exp.X_add_symbol, 661 insn.exp.X_subtract_symbol, 662 insn.exp.X_add_number, 663 1, pcrel_reloc, 664 insn.reloc 665 ); 666 break; 667 668 default: 669 as_warn("Unknown relocation type"); 670 break; 671 } 672} 673 674static 675int 676calcop( 677struct m88k_opcode *format, 678char *param, 679struct m88k_insn *insn) 680{ 681 int parcnt; 682 683 /* initial the passed structure */ 684 685 memset(insn, '\0', sizeof(*insn)); 686 insn->reloc = NO_RELOC; 687 insn->opcode = format->opcode; 688 689 /* parse all parameters */ 690 691 for (parcnt=0; parcnt<3 && format->op[parcnt].type != NIL; parcnt++) { 692 693 switch (format->op[parcnt].type) { 694 695 case CNST: 696 param = parse_cst(param, insn, format, parcnt); 697 break; 698 699 case REG: 700 param = parse_reg(param, insn, format, parcnt); 701 break; 702#ifdef m88110 703 case EREG: 704 param = parse_ereg(param, insn, format, parcnt); 705 break; 706 707 case E4ROT: 708 param = parse_e4rot(param, insn, format,parcnt); 709 break; 710 711 case XREG: 712 param = parse_xreg(param, insn, format, parcnt); 713 break; 714#endif /* m88110 */ 715 case BF: 716 param = parse_bf(param, insn, format, parcnt); 717 break; 718 719 case ROT: 720 param = parse_rot(param, insn, format, parcnt); 721 break; 722 723 case REGSC: 724 param = parse_rsc(param, insn, format, parcnt); 725 break; 726 727 case CRREG: 728 param = parse_cr(param, insn, format, parcnt); 729 break; 730 731 case FCRREG: 732 param = parse_fcr(param, insn, format, parcnt); 733 break; 734 735 case PCREL: 736 param = parse_pcr(param, insn, format, parcnt); 737 break; 738 739 case CONDMASK: 740 param = parse_cnd(param, insn, format, parcnt); 741 break; 742 743 case CMPRSLT: 744 param = parse_cmp(param, insn, format, parcnt); 745 break; 746 747 default: 748 as_fatal("Unknown parameter type"); 749 } 750 751 /* see if parser failed or not */ 752 753 if (param == NULL) 754 return 0; 755 } 756 757 return 1; 758} 759 760static 761char * 762parse_pcr( 763char *param, 764struct m88k_insn *insn, 765struct m88k_opcode *format, 766int parcnt) 767{ 768 char *saveptr, *saveparam; 769 segT seg; 770 771 saveptr = input_line_pointer; 772 input_line_pointer = param; 773 774 seg = expression(&insn->exp); 775 776 saveparam = input_line_pointer; 777 input_line_pointer = saveptr; 778 779 switch (format->op[parcnt].width) { 780 781 case 16: insn->reloc = M88K_RELOC_PC16; 782 break; 783 784 case 26: insn->reloc = M88K_RELOC_PC26; 785 break; 786 787 default: as_warn("Strange PC relative width %d", 788 format->op[parcnt].width); 789 break; 790 } 791 792 return saveparam; 793} 794 795static 796char * 797parse_reg( 798char *param, 799struct m88k_insn *insn, 800struct m88k_opcode *format, 801int parcnt) 802{ 803 unsigned int val = 0; 804 805 if (*param != 'r' && *param != 'R') 806 return NULL; 807 808 param++; 809 810 if (!isdigit(*param)) 811 return NULL; 812 813 while (isdigit(*param)) 814 if ((val = val * 10 + *param++ - '0') > 31) 815 return NULL; 816 817 insn->opcode |= val << format->op[parcnt].offset; 818 819 switch (*param) { 820 821 case '\0' : 822 if (parcnt == 2 || format->op[parcnt+1].type == NIL) 823 return param; 824 else 825 return NULL; 826 827 case '[' : 828 if (parcnt != 2 && format->op[parcnt+1].type == REGSC) 829 return param+1; 830 else 831 return NULL; 832 833 case ',' : 834 if (parcnt != 2 && format->op[parcnt+1].type != NIL) 835 return param+1; 836 else 837 return NULL; 838 } 839 840 return NULL; 841} 842 843#ifdef m88110 844static 845char * 846parse_ereg( 847char *param, 848struct m88k_insn *insn, 849struct m88k_opcode *format, 850int parcnt) 851{ 852 unsigned int val = 0; 853 854 if (*param != 'r' && *param != 'R') 855 return NULL; 856 857 param++; 858 859 if (!isdigit(*param)) 860 return NULL; 861 862 while (isdigit(*param)) 863 if ((val = val * 10 + *param++ - '0') > 31) 864 return NULL; 865 866 if((val & 0x1) != 0) 867 return NULL; 868 869 insn->opcode |= val << format->op[parcnt].offset; 870 871 switch (*param) { 872 873 case '\0' : 874 if (parcnt == 2 || format->op[parcnt+1].type == NIL) 875 return param; 876 else 877 return NULL; 878 879 case '[' : 880 if (parcnt != 2 && format->op[parcnt+1].type == REGSC) 881 return param+1; 882 else 883 return NULL; 884 885 case ',' : 886 if (parcnt != 2 && format->op[parcnt+1].type != NIL) 887 return param+1; 888 else 889 return NULL; 890 } 891 892 return NULL; 893} 894 895static 896char * 897parse_e4rot( 898char *param, 899struct m88k_insn *insn, 900struct m88k_opcode *format, 901int parcnt) 902{ 903 int val; 904 char *saveptr, save_c, *offset_ptr; 905 expressionS exp; 906 segT seg; 907 908 /* Now step over the '<' and look for the offset expression before a 909 '>' and the end of line (which is a '\0' when we get here). We 910 know there is a '\0' where the end of line was because that is 911 what parse_a_buffer() in read.c does before calling md_assemble */ 912 if (*param++ != '<') 913 return NULL; 914 offset_ptr = param; 915 while(*param != '\0') 916 param++; 917 if(param == offset_ptr || param[-1] != '>') 918 return NULL; 919 param--; 920 save_c = *param; 921 *param = '\0'; 922 saveptr = input_line_pointer; 923 input_line_pointer = offset_ptr; 924 seg = expression(&exp); 925 *param = save_c; 926 input_line_pointer = saveptr; 927 val = exp.X_add_number; 928 if(seg != SEG_ABSOLUTE || val > 60 || (val & 0x3) != 0) 929 return NULL; 930 931 val >>= 2; 932 insn->opcode |= val << format->op[parcnt].offset; 933 934 return param+1; 935} 936 937static 938char * 939parse_xreg( 940char *param, 941struct m88k_insn *insn, 942struct m88k_opcode *format, 943int parcnt) 944{ 945 unsigned int val = 0; 946 947 if (*param != 'x' && *param != 'X') 948 return NULL; 949 950 param++; 951 952 if (!isdigit(*param)) 953 return NULL; 954 955 while (isdigit(*param)) 956 if ((val = val * 10 + *param++ - '0') > 31) 957 return NULL; 958 959 insn->opcode |= val << format->op[parcnt].offset; 960 961 switch (*param) { 962 963 case '\0' : 964 if (parcnt == 2 || format->op[parcnt+1].type == NIL) 965 return param; 966 else 967 return NULL; 968 969 case '[' : 970 if (parcnt != 2 && format->op[parcnt+1].type == REGSC) 971 return param+1; 972 else 973 return NULL; 974 975 case ',' : 976 if (parcnt != 2 && format->op[parcnt+1].type != NIL) 977 return param+1; 978 else 979 return NULL; 980 } 981 982 return NULL; 983} 984#endif /* m88110 */ 985 986static 987char * 988parse_cmp( 989char *param, 990struct m88k_insn *insn, 991struct m88k_opcode *format, 992int parcnt) 993{ 994 int val; 995 char *saveptr, save_c, *offset_ptr, c; 996 expressionS exp; 997 segT seg; 998 999 /* look for the offset expression before a ',' */ 1000 c = *param; 1001 if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || 1002 c == '~'){ 1003 offset_ptr = param; 1004 while(*param != ',') 1005 param++; 1006 if(param == offset_ptr || *param != ',') 1007 return NULL; 1008 save_c = *param; 1009 *param = '\0'; 1010 saveptr = input_line_pointer; 1011 input_line_pointer = offset_ptr; 1012 seg = expression(&exp); 1013 *param = save_c; 1014 input_line_pointer = saveptr; 1015 val = exp.X_add_number; 1016 if(seg != SEG_ABSOLUTE || 1017 val > (1 << format->op[parcnt].width) || val < 0) 1018 return NULL; 1019 } else { 1020 if (isupper(*param)) 1021 *param = tolower(*param); 1022 1023 if (isupper(*(param+1))) 1024 *(param+1) = tolower(*(param+1)); 1025 1026 for (val=0; cmpslot[val] != NULL; val++) 1027 if (!strncmp(param,cmpslot[val],2)) 1028 break; 1029 1030 if (cmpslot[val] == NULL) 1031 return NULL; 1032 1033 param += 2; 1034 } 1035 1036 if (*param++ != ',') 1037 return NULL; 1038 1039 insn->opcode |= val << format->op[parcnt].offset; 1040 1041 return param; 1042} 1043 1044static 1045char * 1046parse_cnd( 1047char *param, 1048struct m88k_insn *insn, 1049struct m88k_opcode *format, 1050int parcnt) 1051{ 1052 int val; 1053 char *saveptr, save_c, *offset_ptr, c; 1054 expressionS exp; 1055 segT seg; 1056 1057 /* look for the offset expression before a ',' */ 1058 c = *param; 1059 if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || 1060 c == '~'){ 1061 offset_ptr = param; 1062 while(*param != ',') 1063 param++; 1064 if(param == offset_ptr || *param != ',') 1065 return NULL; 1066 save_c = *param; 1067 *param = '\0'; 1068 saveptr = input_line_pointer; 1069 input_line_pointer = offset_ptr; 1070 seg = expression(&exp); 1071 *param = save_c; 1072 input_line_pointer = saveptr; 1073 val = exp.X_add_number; 1074 if(seg != SEG_ABSOLUTE || 1075 val > (1 << format->op[parcnt].width) || val < 0) 1076 return NULL; 1077 } else { 1078 if (isupper(*param)) 1079 *param = tolower(*param); 1080 1081 if (isupper(*(param+1))) 1082 *(param+1) = tolower(*(param+1)); 1083 1084 for (val=0; cndmsk[val].name != NULL; val++) 1085 if (!strncmp(param,cndmsk[val].name,3)) 1086 break; 1087 1088 if (cndmsk[val].name == NULL) 1089 return NULL; 1090 1091 val = cndmsk[val].num; 1092 1093 param += 3; 1094 } 1095 1096 if (*param++ != ',') 1097 return NULL; 1098 1099 insn->opcode |= val << format->op[parcnt].offset; 1100 1101 return param; 1102} 1103 1104static 1105char * 1106parse_bf( 1107char *param, 1108struct m88k_insn *insn, 1109struct m88k_opcode *format, 1110int parcnt) 1111{ 1112 int val, width; 1113 char *saveptr, save_c, *offset_ptr, c; 1114 expressionS exp; 1115 segT seg; 1116 1117 /* We know there is a '\0' where the end of line was because that is 1118 what parse_a_buffer() in read.c does before calling md_assemble */ 1119 1120 /* First look for the width expression before a '<' */ 1121 saveptr = input_line_pointer; 1122 input_line_pointer = param; 1123 while(*param != '<' && *param != '\0') 1124 param++; 1125 if(*param == '\0'){ 1126 input_line_pointer = saveptr; 1127 return NULL; 1128 } 1129 save_c = *param; 1130 *param = '\0'; 1131 seg = expression(&exp); 1132 *param = save_c; 1133 input_line_pointer = saveptr; 1134 width = exp.X_add_number; 1135 if(seg != SEG_ABSOLUTE || width > 32 || width < 0) 1136 return NULL; 1137 1138 /* Now step over the '<' and look for the offset expression before a 1139 '>' and the end of line (which is a '\0' when we get here) */ 1140 param++; 1141 c = *param; 1142 if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || 1143 c == '~'){ 1144 offset_ptr = param; 1145 while(*param != '\0') 1146 param++; 1147 if(param != offset_ptr && param[-1] != '>') 1148 return NULL; 1149 param--; 1150 save_c = *param; 1151 *param = '\0'; 1152 saveptr = input_line_pointer; 1153 input_line_pointer = offset_ptr; 1154 seg = expression(&exp); 1155 *param = save_c; 1156 input_line_pointer = saveptr; 1157 val = exp.X_add_number; 1158 if(seg != SEG_ABSOLUTE || val > 32 || val < 0) 1159 return NULL; 1160 } 1161 else { 1162 if (isupper(*param)) 1163 *param = tolower(*param); 1164 1165 if (isupper(*(param+1))) 1166 *(param+1) = tolower(*(param+1)); 1167 1168 for (val=0; cmpslot[val] != NULL; val++) 1169 if (!strncmp(param,cmpslot[val],2)) 1170 break; 1171 1172 if (cmpslot[val] == NULL) 1173 return NULL; 1174 1175 param += 2; 1176 } 1177 if (*param != '>') 1178 return NULL; 1179 insn->opcode |= width << 5; 1180 insn->opcode |= val; 1181 1182 return param+1; 1183} 1184 1185static 1186char * 1187parse_rot( 1188char *param, 1189struct m88k_insn *insn, 1190struct m88k_opcode *format, 1191int parcnt) 1192{ 1193 int val; 1194 char *saveptr, save_c, *offset_ptr; 1195 expressionS exp; 1196 segT seg; 1197 1198 /* Now step over the '<' and look for the offset expression before a 1199 '>' and the end of line (which is a '\0' when we get here). We 1200 know there is a '\0' where the end of line was because that is 1201 what parse_a_buffer() in read.c does before calling md_assemble */ 1202 if (*param++ != '<') 1203 return NULL; 1204 offset_ptr = param; 1205 while(*param != '\0') 1206 param++; 1207 if(param != offset_ptr && param[-1] != '>') 1208 return NULL; 1209 param--; 1210 save_c = *param; 1211 *param = '\0'; 1212 saveptr = input_line_pointer; 1213 input_line_pointer = offset_ptr; 1214 seg = expression(&exp); 1215 *param = save_c; 1216 input_line_pointer = saveptr; 1217 val = exp.X_add_number; 1218 if(seg != SEG_ABSOLUTE && (val > 32 || val < 0)) 1219 return NULL; 1220 1221 insn->opcode |= val; 1222 1223 return param+1; 1224} 1225 1226static 1227char * 1228parse_rsc( 1229char *param, 1230struct m88k_insn *insn, 1231struct m88k_opcode *format, 1232int parcnt) 1233{ 1234 unsigned int val = 0; 1235 1236 if (*param != 'r' && *param != 'R') 1237 return NULL; 1238 1239 param++; 1240 1241 if (!isdigit(*param)) 1242 return NULL; 1243 1244 while (isdigit(*param)) 1245 if ((val = val * 10 + *param++ - '0') > 31) 1246 return NULL; 1247 1248 insn->opcode |= val << format->op[parcnt].offset; 1249 1250 if (*param != ']' || *(param+1) != '\0') 1251 return NULL; 1252 1253 return param+1; 1254} 1255 1256static 1257char * 1258parse_cr( 1259char *param, 1260struct m88k_insn *insn, 1261struct m88k_opcode *format, 1262int parcnt) 1263{ 1264 unsigned int val = 0; 1265 1266 if (strncmp(param, "cr", 2)) 1267 return NULL; 1268 1269 param += 2; 1270 1271 if (!isdigit(*param)) 1272 return NULL; 1273 1274 while (isdigit(*param)) 1275 if ((val = val * 10 + *param++ - '0') > 63) 1276 return NULL; 1277 1278 /* 1279 * the following fix is not as generic as I'd like, but the 1280 * hardware is real picky about this. - bowen@cs.buffalo.edu 1281 * This fix is to make sure the S1 and S2 fields are the same. 1282 */ 1283 insn->opcode |= (insn->opcode & 0x001f0000) >> 16; 1284 1285 insn->opcode |= val << format->op[parcnt].offset; 1286 1287 if (*param != '\0') 1288 return NULL; 1289 1290 return param; 1291} 1292 1293static 1294char * 1295parse_fcr( 1296char *param, 1297struct m88k_insn *insn, 1298struct m88k_opcode *format, 1299int parcnt) 1300{ 1301 unsigned int val = 0; 1302 1303 if (strncmp(param, "fcr", 3)) 1304 return NULL; 1305 1306 param += 3; 1307 1308 if (!isdigit(*param)) 1309 return NULL; 1310 1311 while (isdigit(*param)) 1312 if ((val = val * 10 + *param++ - '0') > 63) 1313 return NULL; 1314 1315 /* 1316 * This is to make sure the S1 and S2 fields are the same. 1317 */ 1318 insn->opcode |= (insn->opcode & 0x001f0000) >> 16; 1319 1320 insn->opcode |= val << format->op[parcnt].offset; 1321 1322 if (*param != '\0') 1323 return NULL; 1324 1325 return param; 1326} 1327 1328static 1329char * 1330parse_cst( 1331char *param, 1332struct m88k_insn *insn, 1333struct m88k_opcode *format, 1334int parcnt) 1335{ 1336 char c, *saveptr, *saveparam; 1337 int val, nohilo = 0; 1338 segT seg; 1339 expressionS exp; 1340 1341 c = *param; 1342 if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || 1343 c == '~'){ 1344 saveptr = input_line_pointer; 1345 input_line_pointer = param; 1346 while(*param != '\0') 1347 param++; 1348 seg = expression(&exp); 1349 input_line_pointer = saveptr; 1350 val = exp.X_add_number; 1351 if(seg != SEG_ABSOLUTE || val > (1 << format->op[parcnt].width)) 1352 return NULL; 1353 } 1354 else if (!strncmp(param,"hi16(",5)) 1355 1356 if (isdigit(*(param+5))) { 1357 param = getval(param+5, (unsigned int *)&val); 1358 val = (val & 0xffff0000) >> 16; 1359 if (*param++ != ')') 1360 return NULL; 1361 1362 } else 1363 insn->reloc = M88K_RELOC_HI16; 1364 else if (!strncmp(param,"lo16(",5)) 1365 1366 if (isdigit(*(param+5))) { 1367 param = getval(param+5, (unsigned int *)&val); 1368 val &= 0x0000ffff; 1369 if (*param++ != ')') 1370 return NULL; 1371 1372 } else 1373 insn->reloc = M88K_RELOC_LO16; 1374 1375#ifndef NeXT_MOD 1376 else if (!strncmp(param,"iw16(",5)) 1377 1378 if (isdigit(*(param+5))) { 1379 param = getval(param+5,&val); 1380 val &= 0x0000ffff; 1381 if (*param++ != ')') 1382 return NULL; 1383 1384 } else 1385 insn->reloc = M88K_RELOC_IW16; 1386#endif /* !defined(NeXT_MOD) */ 1387 1388 else if (*param == 'r' && isdigit(*(param+1))) 1389 1390 return NULL; 1391 1392 else { 1393 insn->reloc = M88K_RELOC_LO16; 1394 nohilo = 1; 1395 } 1396 1397 if (insn->reloc != NO_RELOC) { 1398 1399 saveptr = input_line_pointer; 1400 input_line_pointer = param + (nohilo ? 0 : 5); 1401 1402 seg = expression(&insn->exp); 1403 1404 saveparam = input_line_pointer; 1405 input_line_pointer = saveptr; 1406 1407 if (nohilo) { 1408 1409 if (*saveparam != '\0') 1410 return NULL; 1411 1412 return saveparam; 1413 } 1414 1415 if (*saveparam != ')') 1416 return NULL; 1417 1418 return saveparam+1; 1419 } 1420 1421 if ((1 << format->op[parcnt].width) <= val) 1422 return NULL; 1423 1424 insn->opcode |= val << format->op[parcnt].offset; 1425 1426 if (*param != '\0') 1427 return NULL; 1428 1429 return param; 1430} 1431 1432#define isoct(z) (z >= '0' && z <= '7') 1433#define ishex(z) ((z >= '0' && z <= '9') || (z >= 'a' && z <= 'f') || (z >= 'A' && z <= 'F')) 1434#define hexval(z) \ 1435 (isdigit(z) ? (z) - '0' : \ 1436 islower(z) ? (z) - 'a' + 10 : \ 1437 (z) - 'A' + 10) 1438 1439static 1440char * 1441getval( 1442char *param, 1443unsigned int *val) 1444{ 1445 *val = 0; 1446 1447 if (*param == '0' && (*(param+1) == 'x' || *(param+1) == 'X')) 1448 1449 for (param += 2; ishex(*param); param++) 1450 1451 if (*val > 0x0fffffff) 1452 return param; 1453 else 1454 *val = *val * 16 + hexval(*param); 1455 1456 else if (*param == '0') 1457 1458 for (param++; isoct(*param); param++) 1459 1460 if (*val > 0x1fffffff) 1461 return param; 1462 else 1463 *val = *val * 8 + *param - '0'; 1464 1465 else 1466 1467 for (; isdigit(*param); param++) 1468 1469 *val = *val * 10 + *param - '0'; 1470 1471 return param; 1472} 1473 1474void 1475md_number_to_chars( 1476char *buf, 1477signed_expr_t val, 1478int nbytes) 1479{ 1480 switch(nbytes) { 1481 1482 case 4: 1483 *buf++ = val >> 24; 1484 *buf++ = val >> 16; 1485 case 2: 1486 *buf++ = val >> 8; 1487 case 1: 1488 *buf = val; 1489 break; 1490 1491 default: 1492 abort(); 1493 } 1494} 1495 1496void 1497md_number_to_imm( 1498unsigned char *buf, 1499signed_expr_t val, 1500int nbytes, 1501fixS *fixP, 1502int nsect) 1503{ 1504 if(fixP->fx_r_type == NO_RELOC || 1505 fixP->fx_r_type == M88K_RELOC_VANILLA) { 1506 switch (nbytes) { 1507 case 4: 1508 *buf++ = val >> 24; 1509 *buf++ = val >> 16; 1510 case 2: 1511 *buf++ = val >> 8; 1512 case 1: 1513 *buf = val; 1514 break; 1515 1516 default: 1517 abort(); 1518 } 1519 return; 1520 } 1521 1522 switch (fixP->fx_r_type) { 1523#ifdef NeXT_MOD 1524 case M88K_RELOC_LO16: 1525 buf[2] = val >> 8; 1526 buf[3] = val; 1527 break; 1528 case M88K_RELOC_HI16: 1529 buf[2] = val >> 24; 1530 buf[3] = val >> 16; 1531 break; 1532 1533 case M88K_RELOC_PC16: 1534 val += 4; 1535 buf[2] = val >> 10; 1536 buf[3] = val >> 2; 1537 break; 1538 1539 case M88K_RELOC_PC26: 1540 val += 4; 1541 buf[0] |= (val >> 26) & 0x03; 1542 buf[1] = val >> 18; 1543 buf[2] = val >> 10; 1544 buf[3] = val >> 2; 1545 break; 1546#else /* !defined NeXT_MOD */ 1547 case M88K_RELOC_LO16: 1548 buf[0] = val >> 8; 1549 buf[1] = val; 1550 break; 1551 1552 case M88K_RELOC_IW16: 1553 buf[2] = val >> 8; 1554 buf[3] = val; 1555 break; 1556 1557 case M88K_RELOC_HI16: 1558 buf[0] = val >> 24; 1559 buf[1] = val >> 16; 1560 break; 1561 1562 case M88K_RELOC_PC16: 1563 val += 4; 1564 buf[0] = val >> 10; 1565 buf[1] = val >> 2; 1566 break; 1567 1568 case M88K_RELOC_PC26: 1569 val += 4; 1570 buf[0] |= (val >> 26) & 0x03; 1571 buf[1] = val >> 18; 1572 buf[2] = val >> 10; 1573 buf[3] = val >> 2; 1574 break; 1575 1576 case M88K_RELOC_32: 1577 buf[0] = val >> 24; 1578 buf[1] = val >> 16; 1579 buf[2] = val >> 8; 1580 buf[3] = val; 1581 break; 1582#endif /* !defined(NeXT_MOD) */ 1583 1584 default: 1585 as_warn("Bad relocation type"); 1586 break; 1587 } 1588} 1589 1590#define MAX_LITTLENUMS 6 1591 1592/* Turn a string in input_line_pointer into a floating point constant of type 1593 type, and store the appropriate bytes in *litP. The number of LITTLENUMS 1594 emitted is stored in *sizeP . An error message is returned, or NULL on OK. 1595 */ 1596char * 1597md_atof( 1598int type, 1599char *litP, 1600int *sizeP) 1601{ 1602 int prec; 1603 LITTLENUM_TYPE words[MAX_LITTLENUMS]; 1604 LITTLENUM_TYPE *wordP; 1605 char *t; 1606 char *atof_ieee(); 1607 1608 switch(type) { 1609 case 'f': 1610 case 'F': 1611 case 's': 1612 case 'S': 1613 prec = 2; 1614 break; 1615 1616 case 'd': 1617 case 'D': 1618 case 'r': 1619 case 'R': 1620 prec = 4; 1621 break; 1622 1623 case 'x': 1624 case 'X': 1625 prec = 6; 1626 break; 1627 1628 case 'p': 1629 case 'P': 1630 prec = 6; 1631 break; 1632 1633 default: 1634 *sizeP=0; 1635 return "Bad call to MD_ATOF()"; 1636 } 1637 t=atof_ieee(input_line_pointer,type,words); 1638 if(t) 1639 input_line_pointer=t; 1640 1641 *sizeP=prec * sizeof(LITTLENUM_TYPE); 1642 for(wordP=words;prec--;) { 1643 md_number_to_chars(litP,(int32_t)(*wordP++),sizeof(LITTLENUM_TYPE)); 1644 litP+=sizeof(LITTLENUM_TYPE); 1645 } 1646 return ""; /* Someone should teach Dean about null pointers */ 1647} 1648 1649const relax_typeS md_relax_table[] = { {0} }; 1650 1651int 1652md_estimate_size_before_relax( 1653fragS *fragP, 1654int segment_type) 1655{ 1656 as_fatal("internal error: Relaxation should never occur"); 1657 return(0); 1658} 1659 1660void 1661md_convert_frag( 1662fragS *fragP) 1663{ 1664 as_fatal("internal error: Relaxation should never occur"); 1665} 1666 1667void 1668md_end( 1669void) 1670{ 1671} 1672