This is m88k.c in view mode; [Download] [Up]
/* m88k.c -- Assemble for the 88100 Copyright (C) 1989 Free Software Foundation, Inc. This file is not yet part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <ctype.h> #include <string.h> #include <mach-o/m88k/reloc.h> #include "m88k-opcode.h" #include "as.h" #include "flonum.h" #include "expr.h" #include "hash.h" #include "frags.h" #include "fixes.h" #include "read.h" #include "md.h" #include "obstack.h" #include "symbols.h" #include "messages.h" #include "input-scrub.h" #include "sections.h" /* * These are the default cputype and cpusubtype for the m88k architecture. */ const cpu_type_t md_cputype = CPU_TYPE_MC88000; cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_MC88000_ALL; /* This is the byte sex for the m88k architecture */ const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX; #ifdef NeXT static long in_delay_slot = 0; #endif static char *cmpslot[] = { "**", "**", "eq", "ne", "gt", "le", "lt", "ge", "hi", "ls", "lo", "hs", #ifdef m88110 "be", "nb", "he", "nh", #endif m88110 NULL }; static struct { char *name; unsigned int num; } cndmsk[] = { "eq0", 0x02, "ne0", 0x0d, "gt0", 0x01, "lt0", 0x0c, "ge0", 0x03, "le0", 0x0e, NULL, 0x00, }; struct m88k_insn { unsigned long opcode; expressionS exp; #ifdef NeXT enum reloc_type_m88k reloc; #else enum reloc_type reloc; #endif }; static struct hash_control *op_hash = NULL; /* These chars start a comment anywhere in a source file (except inside another comment */ const char md_comment_chars[] = ";"; /* These chars only start a comment at the beginning of a line. */ const char md_line_comment_chars[] = "#"; /* Chars that can be used to separate mant from exp in floating point nums */ const char md_EXP_CHARS[] = "eE"; /* Chars that mean this number is a floating point constant */ /* as in 0f123.456 */ /* or 0H1.234E-12 (see exp chars above) */ const char md_FLT_CHARS[] = "dDfF"; static int calcop( struct m88k_opcode *format, char *param, struct m88k_insn *insn); static char * parse_reg( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); #ifdef m88110 static char *parse_ereg( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_e4rot( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_xreg( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); #endif m88110 static char *parse_pcr( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_cmp( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_cnd( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_bf( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_rot( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_rsc( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_cr( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_fcr( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *parse_cst( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt); static char *getval( char *param, unsigned int *val); #ifdef NeXT static void s_reg( int reg); static void s_scaled( int value); static void s_m88k_abs( int value); static void s_no_delay( int value); static void s_dot( int value); #endif /* NeXT */ const pseudo_typeS md_pseudo_table[] = { #ifdef NeXT {"greg", s_reg, 'r' }, {"xreg", s_reg, 'x' }, {"scaled", s_scaled, 0}, {"abs", s_m88k_abs, 0}, {"no_delay", s_no_delay, 0}, {"dot", s_dot, 0}, #endif #ifndef NeXT /* At NeXT we don't allow these */ {"dfloat", float_cons, 'd'}, {"ffloat", float_cons, 'f'}, {"global", s_globl, 0}, {"half", cons, 2 }, {"ln", s_line, 0}, {"zero", s_space, 0}, {"word", cons, 4 }, #endif {0} }; #ifdef NeXT static void s_dot( int value) { char *name, *end_name, delim; symbolS *symbolP; if( * input_line_pointer == '"') name = input_line_pointer + 1; else name = input_line_pointer; delim = get_symbol_end(); end_name = input_line_pointer; *end_name = 0; symbolP = symbol_find_or_make (name); symbolP -> sy_type = N_ABS; symbolP -> sy_other = 0; /* NO_SECT */ symbolP -> sy_value = obstack_next_free(&frags) - frag_now->fr_literal; symbolP -> sy_frag = &zero_address_frag; *end_name = delim; totally_ignore_line(); } /* * s_reg() is used to implement ".greg symbol,exp" and ".xreg symbol,exp" * which set symbol to 1 or 0 depending on if the expression is a general * register or extended register respectfully. These are intended for use in * macros. */ static void s_reg( int reg) { char *name, *end_name, delim; symbolS *symbolP; unsigned long n_value, val; if( * input_line_pointer == '"') name = input_line_pointer + 1; else name = input_line_pointer; delim = get_symbol_end(); end_name = input_line_pointer; *end_name = delim; SKIP_WHITESPACE(); if ( * input_line_pointer != ',' ) { *end_name = 0; as_warn("Expected comma after name \"%s\"", name); *end_name = delim; ignore_rest_of_line(); return; } input_line_pointer ++; *end_name = 0; SKIP_WHITESPACE(); n_value = 0; if (*input_line_pointer == reg || *input_line_pointer == toupper(reg)){ input_line_pointer++; if(isdigit(*input_line_pointer)){ val = 0; while (isdigit(*input_line_pointer)){ if ((val = val * 10 + *input_line_pointer++ - '0') > 31) break; } SKIP_WHITESPACE(); if(val <= 31 && (*input_line_pointer == '\n' || *input_line_pointer == '@')) n_value = 1; } } symbolP = symbol_find_or_make (name); symbolP -> sy_type = N_ABS; symbolP -> sy_other = 0; /* NO_SECT */ symbolP -> sy_value = n_value; symbolP -> sy_frag = &zero_address_frag; *end_name = delim; totally_ignore_line(); } /* * s_scaled() is used to implement ".scaled symbol,exp" which sets symbol to 1 * or 0 depending on if the expression is a scaled general register expression * "r1[r2]" or not respectfully. This is intended for use in macros. */ static void s_scaled( int value) { char *name, *end_name, delim; symbolS *symbolP; unsigned long n_value, val; if( * input_line_pointer == '"') name = input_line_pointer + 1; else name = input_line_pointer; delim = get_symbol_end(); end_name = input_line_pointer; *end_name = delim; SKIP_WHITESPACE(); if ( * input_line_pointer != ',' ) { *end_name = 0; as_warn("Expected comma after name \"%s\"", name); *end_name = delim; ignore_rest_of_line(); return; } input_line_pointer ++; *end_name = 0; SKIP_WHITESPACE(); n_value = 0; if (*input_line_pointer == 'r' || *input_line_pointer == 'R'){ input_line_pointer++; if(isdigit(*input_line_pointer)){ val = 0; while (isdigit(*input_line_pointer)){ if ((val = val * 10 + *input_line_pointer++ - '0') > 31) break; } SKIP_WHITESPACE(); if(val <= 31 && *input_line_pointer == '['){ input_line_pointer++; if (*input_line_pointer == 'r' || *input_line_pointer == 'R'){ input_line_pointer++; if(isdigit(*input_line_pointer)){ val = 0; while (isdigit(*input_line_pointer)){ if ((val = val * 10 + *input_line_pointer++ - '0') > 31) break; } if(val <= 31 && *input_line_pointer == ']'){ input_line_pointer++; SKIP_WHITESPACE(); if(*input_line_pointer == '\n' || *input_line_pointer == '@') n_value = 1; } } } } } } symbolP = symbol_find_or_make (name); symbolP -> sy_type = N_ABS; symbolP -> sy_other = 0; /* NO_SECT */ symbolP -> sy_value = n_value; symbolP -> sy_frag = & zero_address_frag; *end_name = delim; totally_ignore_line(); } /* * s_m88k_abs() is used to implement ".abs symbol,exp" which sets symbol to 1 * or 0 depending on if the expression is an absolute expression or not * respectfully. This is intended for use in macros. */ static void s_m88k_abs( int value) { char *name, *end_name, delim, *start; symbolS *symbolP; unsigned long n_value, val, is_reg_exp; start = input_line_pointer; if( * input_line_pointer == '"') name = input_line_pointer + 1; else name = input_line_pointer; delim = get_symbol_end(); end_name = input_line_pointer; *end_name = delim; SKIP_WHITESPACE(); if ( * input_line_pointer != ',' ) { *end_name = 0; as_warn("Expected comma after name \"%s\"", name); *end_name = delim; ignore_rest_of_line(); return; } input_line_pointer ++; *end_name = 0; SKIP_WHITESPACE(); is_reg_exp = 0; n_value = 0; if(*input_line_pointer == 'r' || *input_line_pointer == 'R'){ input_line_pointer++; if(isdigit(*input_line_pointer)){ val = 0; while (isdigit(*input_line_pointer)){ if ((val = val * 10 + *input_line_pointer++ - '0') > 31) break; } SKIP_WHITESPACE(); if(val <= 31) is_reg_exp = 1; } } if(is_reg_exp == 0){ *end_name = delim; input_line_pointer = start; s_abs(value); return; } symbolP = symbol_find_or_make (name); symbolP -> sy_type = N_ABS; symbolP -> sy_other = 0; /* NO_SECT */ symbolP -> sy_value = n_value; symbolP -> sy_frag = & zero_address_frag; *end_name = delim; totally_ignore_line(); } /* * s_no_delay() is used to implement ".no_delay string" which will abort and * print the string if the last instruction assembled has a delay slot. * This is intended for use in macros that expand to more than one instruction * that could be put in delay slots. This is not really correct in it's * operation in that it is not per-section and does not take into account * anything other than assembled instructions. */ static void s_no_delay( int value) { char *p, c; p = input_line_pointer; while(*p != '\n' && *p != '@' && *p != '\0') p++; c = *p; *p = '\0'; if(in_delay_slot) as_fatal("delay slot abort %s detected. Assembly stopping.", input_line_pointer); input_line_pointer = p; *p = c; } #endif /* NeXT */ void md_begin( void) { register char *retval = NULL; register unsigned int i = 0; /* initialize hash table */ op_hash = hash_new(); if (op_hash == NULL) as_fatal("Could not initialize hash table"); /* loop until you see the end of the list */ while (*m88k_opcodes[i].name) { char *name = m88k_opcodes[i].name; /* hash each mnemonic and record its position */ retval = hash_insert(op_hash, name, (char *)&m88k_opcodes[i]); if (retval != NULL && *retval != '\0') as_fatal("Can't hash instruction '%s':%s", m88k_opcodes[i].name, retval); /* skip to next unique mnemonic or end of list */ for (i++; !strcmp(m88k_opcodes[i].name, name); i++); } } int md_parse_option( char **argP, int *cntP, char ***vecP) { return (1); } void md_assemble( char *op) { char *param, *thisfrag; struct m88k_opcode *format; struct m88k_insn insn; #ifdef NeXT long pcrel_reloc; #endif assert(op); /* skip over instruction to find parameters */ /* *param != '\0' is need for instructions that have no parameters like rte */ for (param = op; !isspace(*param) && *param != '\0' ; param++); *param++ = '\0'; /* try to find the instruction in the hash table */ if ((format = (struct m88k_opcode *) hash_find(op_hash, op)) == NULL) { as_warn("Invalid mnemonic '%s'", op); return; } /* try parsing this instruction into insn */ while (!calcop(format,param,&insn)) /* if it doesn't parse try the next instruction */ if (!strcmp(format->name, format[1].name)) format++; else { as_warn("Parameter syntax error"); return; } /* grow the current frag and plop in the opcode */ thisfrag = frag_more(4); md_number_to_chars(thisfrag, insn.opcode, 4); #ifdef NeXT in_delay_slot = format->delay_slot; #endif #ifdef NeXT /* generate stabs for debugging assembly code */ /* * If the -g flag is present generate a line number stab for the * instruction. * * See the detailed comments about stabs in read_a_source_file() for a * description of what is going on here. */ if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){ (void)symbol_new( "", 68 /* N_SLINE */, text_nsect, logical_input_line /* n_desc, line number */, obstack_next_free(&frags) - frag_now->fr_literal, frag_now); } #endif /* NeXT */ #ifdef NeXT pcrel_reloc = 0; if (insn.reloc == M88K_RELOC_PC16 || insn.reloc == M88K_RELOC_PC26){ /* * The NeXT linker has the ability to scatter blocks of * sections between labels. This requires that brances to * labels that survive to the link phase must be able to * be relocated. */ if(insn.exp.X_add_symbol != NULL && (insn.exp.X_add_symbol->sy_name[0] != 'L' || flagseen ['L'])) pcrel_reloc = 1; else pcrel_reloc = 0; } #endif /* NeXT */ /* if this instruction requires labels mark it for later */ switch (insn.reloc) { case NO_RELOC: break; case M88K_RELOC_LO16: case M88K_RELOC_HI16: fix_new( frag_now, #ifdef NeXT thisfrag - frag_now->fr_literal, 4, #else thisfrag - frag_now->fr_literal + 2, 2, #endif insn.exp.X_add_symbol, insn.exp.X_subtract_symbol, insn.exp.X_add_number, 0, 0, insn.reloc ); break; #ifndef NeXT case M88K_RELOC_IW16: fix_new( frag_now, thisfrag - frag_now->fr_literal, 4, insn.exp.X_add_symbol, insn.exp.X_subtract_symbol, insn.exp.X_add_number, 0, 0, insn.reloc ); break; #endif /* !defined(NeXT) */ case M88K_RELOC_PC16: fix_new( frag_now, #ifdef NeXT thisfrag - frag_now->fr_literal, 4, #else thisfrag - frag_now->fr_literal + 2, 2, #endif insn.exp.X_add_symbol, insn.exp.X_subtract_symbol, insn.exp.X_add_number, 1, pcrel_reloc, insn.reloc ); break; case M88K_RELOC_PC26: fix_new( frag_now, thisfrag - frag_now->fr_literal, 4, insn.exp.X_add_symbol, insn.exp.X_subtract_symbol, insn.exp.X_add_number, 1, pcrel_reloc, insn.reloc ); break; default: as_warn("Unknown relocation type"); break; } } static int calcop( struct m88k_opcode *format, char *param, struct m88k_insn *insn) { int parcnt; /* initial the passed structure */ memset(insn, '\0', sizeof(*insn)); insn->reloc = NO_RELOC; insn->opcode = format->opcode; /* parse all parameters */ for (parcnt=0; parcnt<3 && format->op[parcnt].type != NIL; parcnt++) { switch (format->op[parcnt].type) { case CNST: param = parse_cst(param, insn, format, parcnt); break; case REG: param = parse_reg(param, insn, format, parcnt); break; #ifdef m88110 case EREG: param = parse_ereg(param, insn, format, parcnt); break; case E4ROT: param = parse_e4rot(param, insn, format,parcnt); break; case XREG: param = parse_xreg(param, insn, format, parcnt); break; #endif m88110 case BF: param = parse_bf(param, insn, format, parcnt); break; case ROT: param = parse_rot(param, insn, format, parcnt); break; case REGSC: param = parse_rsc(param, insn, format, parcnt); break; case CRREG: param = parse_cr(param, insn, format, parcnt); break; case FCRREG: param = parse_fcr(param, insn, format, parcnt); break; case PCREL: param = parse_pcr(param, insn, format, parcnt); break; case CONDMASK: param = parse_cnd(param, insn, format, parcnt); break; case CMPRSLT: param = parse_cmp(param, insn, format, parcnt); break; default: as_fatal("Unknown parameter type"); } /* see if parser failed or not */ if (param == NULL) return 0; } return 1; } static char * parse_pcr( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { char *saveptr, *saveparam; segT seg; saveptr = input_line_pointer; input_line_pointer = param; seg = expression(&insn->exp); saveparam = input_line_pointer; input_line_pointer = saveptr; switch (format->op[parcnt].width) { case 16: insn->reloc = M88K_RELOC_PC16; break; case 26: insn->reloc = M88K_RELOC_PC26; break; default: as_warn("Strange PC relative width %d", format->op[parcnt].width); break; } return saveparam; } static char * parse_reg( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { unsigned int val = 0; if (*param != 'r' && *param != 'R') return NULL; param++; if (!isdigit(*param)) return NULL; while (isdigit(*param)) if ((val = val * 10 + *param++ - '0') > 31) return NULL; insn->opcode |= val << format->op[parcnt].offset; switch (*param) { case '\0' : if (parcnt == 2 || format->op[parcnt+1].type == NIL) return param; else return NULL; case '[' : if (parcnt != 2 && format->op[parcnt+1].type == REGSC) return param+1; else return NULL; case ',' : if (parcnt != 2 && format->op[parcnt+1].type != NIL) return param+1; else return NULL; } return NULL; } #ifdef m88110 static char * parse_ereg( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { unsigned int val = 0; if (*param != 'r' && *param != 'R') return NULL; param++; if (!isdigit(*param)) return NULL; while (isdigit(*param)) if ((val = val * 10 + *param++ - '0') > 31) return NULL; if((val & 0x1) != 0) return NULL; insn->opcode |= val << format->op[parcnt].offset; switch (*param) { case '\0' : if (parcnt == 2 || format->op[parcnt+1].type == NIL) return param; else return NULL; case '[' : if (parcnt != 2 && format->op[parcnt+1].type == REGSC) return param+1; else return NULL; case ',' : if (parcnt != 2 && format->op[parcnt+1].type != NIL) return param+1; else return NULL; } return NULL; } static char * parse_e4rot( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { int val; char *saveptr, save_c, *offset_ptr; expressionS exp; segT seg; /* Now step over the '<' and look for the offset expression before a '>' and the end of line (which is a '\0' when we get here). We know there is a '\0' where the end of line was because that is what parse_a_buffer() in read.c does before calling md_assemble */ if (*param++ != '<') return NULL; offset_ptr = param; while(*param != '\0') param++; if(param == offset_ptr || param[-1] != '>') return NULL; param--; save_c = *param; *param = '\0'; saveptr = input_line_pointer; input_line_pointer = offset_ptr; seg = expression(&exp); *param = save_c; input_line_pointer = saveptr; val = exp.X_add_number; if(seg != SEG_ABSOLUTE || val > 60 || (val & 0x3) != 0) return NULL; val >>= 2; insn->opcode |= val << format->op[parcnt].offset; return param+1; } static char * parse_xreg( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { unsigned int val = 0; if (*param != 'x' && *param != 'X') return NULL; param++; if (!isdigit(*param)) return NULL; while (isdigit(*param)) if ((val = val * 10 + *param++ - '0') > 31) return NULL; insn->opcode |= val << format->op[parcnt].offset; switch (*param) { case '\0' : if (parcnt == 2 || format->op[parcnt+1].type == NIL) return param; else return NULL; case '[' : if (parcnt != 2 && format->op[parcnt+1].type == REGSC) return param+1; else return NULL; case ',' : if (parcnt != 2 && format->op[parcnt+1].type != NIL) return param+1; else return NULL; } return NULL; } #endif m88110 static char * parse_cmp( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { int val; char *saveptr, save_c, *offset_ptr, c; expressionS exp; segT seg; /* look for the offset expression before a ',' */ c = *param; if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || c == '~'){ offset_ptr = param; while(*param != ',') param++; if(param == offset_ptr || *param != ',') return NULL; save_c = *param; *param = '\0'; saveptr = input_line_pointer; input_line_pointer = offset_ptr; seg = expression(&exp); *param = save_c; input_line_pointer = saveptr; val = exp.X_add_number; if(seg != SEG_ABSOLUTE || val > (1 << format->op[parcnt].width) || val < 0) return NULL; } else { if (isupper(*param)) *param = tolower(*param); if (isupper(*(param+1))) *(param+1) = tolower(*(param+1)); for (val=0; cmpslot[val] != NULL; val++) if (!strncmp(param,cmpslot[val],2)) break; if (cmpslot[val] == NULL) return NULL; param += 2; } if (*param++ != ',') return NULL; insn->opcode |= val << format->op[parcnt].offset; return param; } static char * parse_cnd( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { int val; char *saveptr, save_c, *offset_ptr, c; expressionS exp; segT seg; /* look for the offset expression before a ',' */ c = *param; if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || c == '~'){ offset_ptr = param; while(*param != ',') param++; if(param == offset_ptr || *param != ',') return NULL; save_c = *param; *param = '\0'; saveptr = input_line_pointer; input_line_pointer = offset_ptr; seg = expression(&exp); *param = save_c; input_line_pointer = saveptr; val = exp.X_add_number; if(seg != SEG_ABSOLUTE || val > (1 << format->op[parcnt].width) || val < 0) return NULL; } else { if (isupper(*param)) *param = tolower(*param); if (isupper(*(param+1))) *(param+1) = tolower(*(param+1)); for (val=0; cndmsk[val].name != NULL; val++) if (!strncmp(param,cndmsk[val].name,3)) break; if (cndmsk[val].name == NULL) return NULL; val = cndmsk[val].num; param += 3; } if (*param++ != ',') return NULL; insn->opcode |= val << format->op[parcnt].offset; return param; } static char * parse_bf( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { int val, width; char *saveptr, save_c, *offset_ptr, c; expressionS exp; segT seg; /* We know there is a '\0' where the end of line was because that is what parse_a_buffer() in read.c does before calling md_assemble */ /* First look for the width expression before a '<' */ saveptr = input_line_pointer; input_line_pointer = param; while(*param != '<' && *param != '\0') param++; if(*param == '\0'){ input_line_pointer = saveptr; return NULL; } save_c = *param; *param = '\0'; seg = expression(&exp); *param = save_c; input_line_pointer = saveptr; width = exp.X_add_number; if(seg != SEG_ABSOLUTE || width > 32 || width < 0) return NULL; /* Now step over the '<' and look for the offset expression before a '>' and the end of line (which is a '\0' when we get here) */ param++; c = *param; if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || c == '~'){ offset_ptr = param; while(*param != '\0') param++; if(param != offset_ptr && param[-1] != '>') return NULL; param--; save_c = *param; *param = '\0'; saveptr = input_line_pointer; input_line_pointer = offset_ptr; seg = expression(&exp); *param = save_c; input_line_pointer = saveptr; val = exp.X_add_number; if(seg != SEG_ABSOLUTE || val > 32 || val < 0) return NULL; } else { if (isupper(*param)) *param = tolower(*param); if (isupper(*(param+1))) *(param+1) = tolower(*(param+1)); for (val=0; cmpslot[val] != NULL; val++) if (!strncmp(param,cmpslot[val],2)) break; if (cmpslot[val] == NULL) return NULL; param += 2; } if (*param != '>') return NULL; insn->opcode |= width << 5; insn->opcode |= val; return param+1; } static char * parse_rot( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { int val; char *saveptr, save_c, *offset_ptr; expressionS exp; segT seg; /* Now step over the '<' and look for the offset expression before a '>' and the end of line (which is a '\0' when we get here). We know there is a '\0' where the end of line was because that is what parse_a_buffer() in read.c does before calling md_assemble */ if (*param++ != '<') return NULL; offset_ptr = param; while(*param != '\0') param++; if(param != offset_ptr && param[-1] != '>') return NULL; param--; save_c = *param; *param = '\0'; saveptr = input_line_pointer; input_line_pointer = offset_ptr; seg = expression(&exp); *param = save_c; input_line_pointer = saveptr; val = exp.X_add_number; if(seg != SEG_ABSOLUTE && (val > 32 || val < 0)) return NULL; insn->opcode |= val; return param+1; } static char * parse_rsc( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { unsigned int val = 0; if (*param != 'r' && *param != 'R') return NULL; param++; if (!isdigit(*param)) return NULL; while (isdigit(*param)) if ((val = val * 10 + *param++ - '0') > 31) return NULL; insn->opcode |= val << format->op[parcnt].offset; if (*param != ']' || *(param+1) != '\0') return NULL; return param+1; } static char * parse_cr( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { unsigned int val = 0; if (strncmp(param, "cr", 2)) return NULL; param += 2; if (!isdigit(*param)) return NULL; while (isdigit(*param)) if ((val = val * 10 + *param++ - '0') > 63) return NULL; /* * the following fix is not as generic as I'd like, but the * hardware is real picky about this. - bowen@cs.buffalo.edu * This fix is to make sure the S1 and S2 fields are the same. */ insn->opcode |= (insn->opcode & 0x001f0000) >> 16; insn->opcode |= val << format->op[parcnt].offset; if (*param != '\0') return NULL; return param; } static char * parse_fcr( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { unsigned int val = 0; if (strncmp(param, "fcr", 3)) return NULL; param += 3; if (!isdigit(*param)) return NULL; while (isdigit(*param)) if ((val = val * 10 + *param++ - '0') > 63) return NULL; /* * This is to make sure the S1 and S2 fields are the same. */ insn->opcode |= (insn->opcode & 0x001f0000) >> 16; insn->opcode |= val << format->op[parcnt].offset; if (*param != '\0') return NULL; return param; } static char * parse_cst( char *param, struct m88k_insn *insn, struct m88k_opcode *format, int parcnt) { char c, *saveptr, *saveparam; unsigned int val, nohilo = 0; segT seg; expressionS exp; c = *param; if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' || c == '~'){ saveptr = input_line_pointer; input_line_pointer = param; while(*param != '\0') param++; seg = expression(&exp); input_line_pointer = saveptr; val = exp.X_add_number; if(seg != SEG_ABSOLUTE || val > (1 << format->op[parcnt].width)) return NULL; } else if (!strncmp(param,"hi16(",5)) if (isdigit(*(param+5))) { param = getval(param+5,&val); val = (val & 0xffff0000) >> 16; if (*param++ != ')') return NULL; } else insn->reloc = M88K_RELOC_HI16; else if (!strncmp(param,"lo16(",5)) if (isdigit(*(param+5))) { param = getval(param+5,&val); val &= 0x0000ffff; if (*param++ != ')') return NULL; } else insn->reloc = M88K_RELOC_LO16; #ifndef NeXT else if (!strncmp(param,"iw16(",5)) if (isdigit(*(param+5))) { param = getval(param+5,&val); val &= 0x0000ffff; if (*param++ != ')') return NULL; } else insn->reloc = M88K_RELOC_IW16; #endif /* !defined(NeXT) */ else if (*param == 'r' && isdigit(*(param+1))) return NULL; else { insn->reloc = M88K_RELOC_LO16; nohilo = 1; } if (insn->reloc != NO_RELOC) { saveptr = input_line_pointer; input_line_pointer = param + (nohilo ? 0 : 5); seg = expression(&insn->exp); saveparam = input_line_pointer; input_line_pointer = saveptr; if (nohilo) { if (*saveparam != '\0') return NULL; return saveparam; } if (*saveparam != ')') return NULL; return saveparam+1; } if ((1 << format->op[parcnt].width) <= val) return NULL; insn->opcode |= val << format->op[parcnt].offset; if (*param != '\0') return NULL; return param; } #define isoct(z) (z >= '0' && z <= '7') #define ishex(z) ((z >= '0' && z <= '9') || (z >= 'a' && z <= 'f') || (z >= 'A' && z <= 'F')) #define hexval(z) \ (isdigit(z) ? (z) - '0' : \ islower(z) ? (z) - 'a' + 10 : \ (z) - 'A' + 10) static char * getval( char *param, unsigned int *val) { *val = 0; if (*param == '0' && (*(param+1) == 'x' || *(param+1) == 'X')) for (param += 2; ishex(*param); param++) if (*val > 0x0fffffff) return param; else *val = *val * 16 + hexval(*param); else if (*param == '0') for (param++; isoct(*param); param++) if (*val > 0x1fffffff) return param; else *val = *val * 8 + *param - '0'; else for (; isdigit(*param); param++) *val = *val * 10 + *param - '0'; return param; } void md_number_to_chars( char *buf, long val, int nbytes) { switch(nbytes) { case 4: *buf++ = val >> 24; *buf++ = val >> 16; case 2: *buf++ = val >> 8; case 1: *buf = val; break; default: abort(); } } void md_number_to_imm( unsigned char *buf, long val, int nbytes, fixS *fixP, int nsect) { if(fixP->fx_r_type == NO_RELOC || fixP->fx_r_type == M88K_RELOC_VANILLA) { switch (nbytes) { case 4: *buf++ = val >> 24; *buf++ = val >> 16; case 2: *buf++ = val >> 8; case 1: *buf = val; break; default: abort(); } return; } switch (fixP->fx_r_type) { #ifdef NeXT case M88K_RELOC_LO16: buf[2] = val >> 8; buf[3] = val; break; case M88K_RELOC_HI16: buf[2] = val >> 24; buf[3] = val >> 16; break; case M88K_RELOC_PC16: val += 4; buf[2] = val >> 10; buf[3] = val >> 2; break; case M88K_RELOC_PC26: val += 4; buf[0] |= (val >> 26) & 0x03; buf[1] = val >> 18; buf[2] = val >> 10; buf[3] = val >> 2; break; #else /* !defined NeXT */ case M88K_RELOC_LO16: buf[0] = val >> 8; buf[1] = val; break; case M88K_RELOC_IW16: buf[2] = val >> 8; buf[3] = val; break; case M88K_RELOC_HI16: buf[0] = val >> 24; buf[1] = val >> 16; break; case M88K_RELOC_PC16: val += 4; buf[0] = val >> 10; buf[1] = val >> 2; break; case M88K_RELOC_PC26: val += 4; buf[0] |= (val >> 26) & 0x03; buf[1] = val >> 18; buf[2] = val >> 10; buf[3] = val >> 2; break; case M88K_RELOC_32: buf[0] = val >> 24; buf[1] = val >> 16; buf[2] = val >> 8; buf[3] = val; break; #endif /* !defined(NeXT) */ default: as_warn("Bad relocation type"); break; } } #define MAX_LITTLENUMS 6 /* Turn a string in input_line_pointer into a floating point constant of type type, and store the appropriate bytes in *litP. The number of LITTLENUMS emitted is stored in *sizeP . An error message is returned, or NULL on OK. */ char * md_atof( int type, char *litP, int *sizeP) { int prec; LITTLENUM_TYPE words[MAX_LITTLENUMS]; LITTLENUM_TYPE *wordP; char *t; char *atof_ieee(); switch(type) { case 'f': case 'F': case 's': case 'S': prec = 2; break; case 'd': case 'D': case 'r': case 'R': prec = 4; break; case 'x': case 'X': prec = 6; break; case 'p': case 'P': prec = 6; break; default: *sizeP=0; return "Bad call to MD_ATOF()"; } t=atof_ieee(input_line_pointer,type,words); if(t) input_line_pointer=t; *sizeP=prec * sizeof(LITTLENUM_TYPE); for(wordP=words;prec--;) { md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); litP+=sizeof(LITTLENUM_TYPE); } return ""; /* Someone should teach Dean about null pointers */ } const relax_typeS md_relax_table[] = {0}; int md_estimate_size_before_relax( fragS *fragP, int segment_type) { as_fatal("internal error: Relaxation should never occur"); return(0); } void md_convert_frag( fragS *fragP) { as_fatal("internal error: Relaxation should never occur"); } void md_end( void) { }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.