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