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