Initial import from FreeBSD RELENG_4:
[games.git] / gnu / usr.bin / as / config / tc-m88k.c
1 /* m88k.c -- Assembler for the Motorola 88000
2    Contributed by Devon Bowen of Buffalo University
3    and Torbjorn Granlund of the Swedish Institute of Computer Science.
4    Copyright (C) 1989-1992 Free Software Foundation, Inc.
5
6    This file is part of GAS, the GNU Assembler.
7
8    GAS is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12
13    GAS is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GAS; see the file COPYING.  If not, write to
20    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
21
22 #include "as.h"
23 #include "opcode/m88k.h"
24
25 struct m88k_insn
26 {
27   unsigned long opcode;
28   expressionS exp;
29   enum reloc_type reloc;
30 };
31
32 #if __STDC__ == 1
33
34 static int calcop(struct m88k_opcode *format, char *param, struct m88k_insn *insn);
35
36 #else /* not __STDC__ */
37
38 static int calcop();
39
40 #endif /* not __STDC__ */
41
42 char *getval ();
43 char *get_reg ();
44 char *get_imm16 ();
45 char *get_bf ();
46 char *get_pcr ();
47 char *get_cmp ();
48 char *get_cnd ();
49 char *get_cr ();
50 char *get_fcr ();
51 char *get_vec9 ();
52
53 struct field_val_assoc
54 {
55   char *name;
56   unsigned val;
57 };
58
59 struct field_val_assoc cr_regs[] =
60 {
61   {"PID", 0},
62   {"PSR", 1},
63   {"EPSR", 2},
64   {"SSBR", 3},
65   {"SXIP", 4},
66   {"SNIP", 5},
67   {"SFIP", 6},
68   {"VBR", 7},
69   {"DMT0", 8},
70   {"DMD0", 9},
71   {"DMA0", 10},
72   {"DMT1", 11},
73   {"DMD1", 12},
74   {"DMA1", 13},
75   {"DMT2", 14},
76   {"DMD2", 15},
77   {"DMA2", 16},
78   {"SR0", 17},
79   {"SR1", 18},
80   {"SR2", 19},
81   {"SR3", 20},
82
83   {NULL, 0},
84 };
85
86 struct field_val_assoc fcr_regs[] =
87 {
88   {"FPECR", 0},
89   {"FPHS1", 1},
90   {"FPLS1", 2},
91   {"FPHS2", 3},
92   {"FPLS2", 4},
93   {"FPPT", 5},
94   {"FPRH", 6},
95   {"FPRL", 7},
96   {"FPIT", 8},
97
98   {"FPSR", 62},
99   {"FPCR", 63},
100
101   {NULL, 0},
102 };
103
104 struct field_val_assoc cmpslot[] =
105 {
106 /* Integer  Floating point */
107                 {"nc", 0},
108                 {"cp", 1},
109   {"eq", 2},
110   {"ne", 3},
111   {"gt", 4},
112   {"le", 5},
113   {"lt", 6},
114   {"ge", 7},
115   {"hi", 8},    {"ou", 8},
116   {"ls", 9},    {"ib", 9},
117   {"lo", 10},   {"in", 10},
118   {"hs", 11},   {"ob", 11},
119
120   {NULL, 0},
121 };
122
123 struct field_val_assoc cndmsk[] =
124 {
125   {"gt0", 1},
126   {"eq0", 2},
127   {"ge0", 3},
128   {"lt0", 12},
129   {"ne0", 13},
130   {"le0", 14},
131
132   {NULL, 0},
133 };
134
135 extern char *myname;
136 static struct hash_control *op_hash = NULL;
137
138 /* These bits should be turned off in the first address of every segment */
139 int md_seg_align = 7;
140
141 /* This is the number to put at the beginning of the a.out file */
142 long omagic = OMAGIC;
143
144 /* These chars start a comment anywhere in a source file (except inside
145    another comment */
146 char comment_chars[] = ";";
147
148 /* These chars only start a comment at the beginning of a line. */
149 char line_comment_chars[] = "#";
150
151 /* Chars that can be used to separate mant from exp in floating point nums */
152 char EXP_CHARS[] = "eE";
153
154 /* Chars that mean this number is a floating point constant */
155 /* as in 0f123.456 */
156 /* or    0H1.234E-12 (see exp chars above) */
157 char FLT_CHARS[] = "dDfF";
158
159 extern void float_cons (), cons (), s_globl (), s_line (),
160   s_space (), s_set (), stringer (), s_lcomm ();
161 static void s_bss ();
162
163 const pseudo_typeS md_pseudo_table[] = {
164         {"align", s_align_bytes, 0 },
165         {"def", s_set, 0},
166         {"dfloat", float_cons, 'd'},
167         {"ffloat", float_cons, 'f'},
168         {"global", s_globl, 0},
169         {"half", cons, 2 },
170         {"bss", s_bss, 0},
171         {"string", stringer, 0},
172         {"word", cons, 4 },
173         {"zero", s_space, 0},
174         {0}
175 };
176
177 const int md_reloc_size = 12; /* Size of relocation record */
178
179 void
180 md_begin ()
181 {
182   char *retval = NULL;
183   unsigned int i = 0;
184
185   /* initialize hash table */
186
187   op_hash = hash_new ();
188   if (op_hash == NULL)
189     as_fatal ("Could not initialize hash table");
190
191   /* loop until you see the end of the list */
192
193   while (*m88k_opcodes[i].name)
194     {
195       char *name = m88k_opcodes[i].name;
196
197       /* hash each mnemonic and record its position */
198
199       retval = hash_insert (op_hash, name, &m88k_opcodes[i]);
200
201       if (retval != NULL && *retval != '\0')
202         as_fatal ("Can't hash instruction '%s':%s",
203                  m88k_opcodes[i].name, retval);
204
205       /* skip to next unique mnemonic or end of list */
206
207       for (i++; !strcmp (m88k_opcodes[i].name, name); i++)
208         ;
209     }
210 }
211
212 int
213 md_parse_option (argP, cntP, vecP)
214      char **argP;
215      int *cntP;
216      char ***vecP;
217 {
218         as_warn ("unknown option: -%s", *argP);
219         return(0);
220 }
221
222 void
223 md_assemble (op)
224      char *op;
225 {
226   char *param, *thisfrag;
227   struct m88k_opcode *format;
228   struct m88k_insn insn;
229
230   assert (op);
231
232   /* skip over instruction to find parameters */
233
234   for (param = op; *param != 0 && !isspace (*param); param++)
235     ;
236   if (*param != 0)
237     *param++ = 0;
238
239   /* try to find the instruction in the hash table */
240
241   if ((format = (struct m88k_opcode *) hash_find (op_hash, op)) == NULL)
242     {
243       as_fatal ("Invalid mnemonic '%s'", op);
244       return;
245     }
246
247   /* try parsing this instruction into insn */
248
249   insn.exp.X_add_symbol = 0;
250   insn.exp.X_subtract_symbol = 0;
251   insn.exp.X_add_number = 0;
252   insn.exp.X_seg = 0;
253   insn.reloc = NO_RELOC;
254
255   while (!calcop(format, param, &insn))
256     {
257       /* if it doesn't parse try the next instruction */
258
259       if (!strcmp (format[0].name, format[1].name))
260         format++;
261       else
262         {
263           as_fatal ("Parameter syntax error");
264           return;
265         }
266     }
267
268   /* grow the current frag and plop in the opcode */
269
270   thisfrag = frag_more (4);
271   md_number_to_chars (thisfrag, insn.opcode, 4);
272
273   /* if this instruction requires labels mark it for later */
274
275   switch (insn.reloc)
276     {
277     case NO_RELOC:
278       break;
279
280     case RELOC_LO16:
281     case RELOC_HI16:
282       fix_new (frag_now,
283                thisfrag - frag_now->fr_literal + 2,
284                2,
285                insn.exp.X_add_symbol,
286                insn.exp.X_subtract_symbol,
287                insn.exp.X_add_number,
288                0,
289                insn.reloc);
290       break;
291
292     case RELOC_IW16:
293       fix_new (frag_now,
294                thisfrag - frag_now->fr_literal,
295                4,
296                insn.exp.X_add_symbol,
297                insn.exp.X_subtract_symbol,
298                insn.exp.X_add_number,
299                0,
300                insn.reloc);
301       break;
302
303     case RELOC_PC16:
304       fix_new (frag_now,
305                thisfrag - frag_now->fr_literal + 2,
306                2,
307                insn.exp.X_add_symbol,
308                insn.exp.X_subtract_symbol,
309                insn.exp.X_add_number,
310                1,
311                insn.reloc);
312       break;
313
314     case RELOC_PC26:
315       fix_new (frag_now,
316                thisfrag - frag_now->fr_literal,
317                4,
318                insn.exp.X_add_symbol,
319                insn.exp.X_subtract_symbol,
320                insn.exp.X_add_number,
321                1,
322                insn.reloc);
323       break;
324
325     default:
326       as_fatal ("Unknown relocation type");
327       break;
328     }
329 }
330
331 int
332 calcop (format, param, insn)
333      struct m88k_opcode *format;
334      char *param;
335      struct m88k_insn *insn;
336 {
337   char *fmt = format->op_spec;
338   int f;
339   unsigned val;
340   unsigned opcode;
341
342   insn->opcode = format->opcode;
343   opcode = 0;
344
345   for (;;)
346     {
347       if (param == 0)
348         return 0;
349       f = *fmt++;
350       switch (f)
351         {
352         case 0:
353           insn->opcode |= opcode;
354           return *param == 0;
355
356         default:
357           if (f != *param++)
358             return 0;
359           break;
360
361         case 'd':
362           param = get_reg (param, &val);
363           opcode |= val << 21;
364           break;
365
366         case '1':
367           param = get_reg (param, &val);
368           opcode |= val << 16;
369           break;
370
371         case '2':
372           param = get_reg (param, &val);
373           opcode |= val;
374           break;
375
376         case '3':
377           param = get_reg (param, &val);
378           opcode |= (val << 16) | val;
379           break;
380
381         case 'I':
382           param = get_imm16 (param, insn);
383           break;
384
385         case 'b':
386           param = get_bf (param, &val);
387           opcode |= val;
388           break;
389
390         case 'p':
391           param = get_pcr (param, insn, RELOC_PC16);
392           break;
393
394         case 'P':
395           param = get_pcr (param, insn, RELOC_PC26);
396           break;
397
398         case 'B':
399           param = get_cmp (param, &val);
400           opcode |= val;
401           break;
402
403         case 'M':
404           param = get_cnd (param, &val);
405           opcode |= val;
406           break;
407
408         case 'c':
409           param = get_cr (param, &val);
410           opcode |= val << 5;
411           break;
412
413         case 'f':
414           param = get_fcr (param, &val);
415           opcode |= val << 5;
416           break;
417
418         case 'V':
419           param = get_vec9 (param, &val);
420           opcode |= val;
421           break;
422
423         case '?':
424           /* Having this here repeats the warning somtimes.
425            But can't we stand that?  */
426           as_warn ("Use of obsolete instruction");
427           break;
428         }
429     }
430 }
431
432 char *
433 match_name (param, assoc_tab, valp)
434      char *param;
435      struct field_val_assoc *assoc_tab;
436      unsigned *valp;
437 {
438   int i;
439   char *name;
440   int name_len;
441
442   for (i = 0;; i++)
443     {
444       name = assoc_tab[i].name;
445       if (name == NULL)
446         return NULL;
447       name_len = strlen (name);
448       if (!strncmp (param, name, name_len))
449         {
450           *valp = assoc_tab[i].val;
451           return param + name_len;
452         }
453     }
454 }
455
456 char *
457 get_reg (param, regnop)
458      char *param;
459      unsigned *regnop;
460 {
461   unsigned c;
462   unsigned regno;
463
464   c = *param++;
465   if (c == 'r')
466     {
467       regno = *param++ - '0';
468       if (regno < 10)
469         {
470           if (regno == 0)
471             {
472               *regnop = 0;
473               return param;
474             }
475           c = *param - '0';
476           if (c < 10)
477             {
478               regno = regno * 10 + c;
479               if (c < 32)
480                 {
481                   *regnop = regno;
482                   return param + 1;
483                 }
484             }
485           else
486             {
487               *regnop = regno;
488               return param;
489             }
490         }
491       return NULL;
492     }
493   else if (c == 's' && param[0] == 'p')
494     {
495       *regnop = 31;
496       return param + 1;
497     }
498
499   return 0;
500 }
501
502 char *
503 get_imm16 (param, insn)
504      char *param;
505      struct m88k_insn *insn;
506 {
507   enum reloc_type reloc = NO_RELOC;
508   unsigned int val;
509   segT seg;
510   char *save_ptr;
511
512   if (!strncmp (param, "hi16", 4) && !isalnum (param[4]))
513     {
514       reloc = RELOC_HI16;
515       param += 4;
516     }
517   else if (!strncmp (param, "lo16", 4) && !isalnum (param[4]))
518     {
519       reloc = RELOC_LO16;
520       param += 4;
521     }
522   else if (!strncmp (param, "iw16", 4) && !isalnum (param[4]))
523     {
524       reloc = RELOC_IW16;
525       param += 4;
526     }
527
528   save_ptr = input_line_pointer;
529   input_line_pointer = param;
530   seg = expression (&insn->exp);
531   param = input_line_pointer;
532   input_line_pointer = save_ptr;
533
534   val = insn->exp.X_add_number;
535
536   if (seg == SEG_ABSOLUTE)
537     {
538       /* Insert the value now, and reset reloc to NO_RELOC.  */
539       if (reloc == NO_RELOC)
540         {
541           /* Warn about too big expressions if not surrounded by xx16.  */
542           if (val > 0xffff)
543             as_warn ("Expression truncated to 16 bits");
544         }
545
546       if (reloc == RELOC_HI16)
547         val >>= 16;
548
549       insn->opcode |= val & 0xffff;
550       reloc = NO_RELOC;
551     }
552   else if (reloc == NO_RELOC)
553     /* We accept a symbol even without lo16, hi16, etc, and assume
554        lo16 was intended.  */
555     reloc = RELOC_LO16;
556
557   insn->reloc = reloc;
558
559   return param;
560 }
561
562 char *
563 get_pcr (param, insn, reloc)
564      char *param;
565      struct m88k_insn *insn;
566      enum reloc_type reloc;
567 {
568   char *saveptr, *saveparam;
569   segT seg;
570
571   saveptr = input_line_pointer;
572   input_line_pointer = param;
573
574   seg = expression (&insn->exp);
575
576   saveparam = input_line_pointer;
577   input_line_pointer = saveptr;
578
579   /* Botch: We should relocate now if SEG_ABSOLUTE.  */
580   insn->reloc = reloc;
581
582   return saveparam;
583 }
584
585 char *
586 get_cmp (param, valp)
587      char *param;
588      unsigned *valp;
589 {
590   unsigned int val;
591   char *save_ptr;
592
593   save_ptr = param;
594
595   param = match_name (param, cmpslot, valp);
596   val = *valp;
597
598   if (param == NULL)
599     {
600       param = save_ptr;
601
602       save_ptr = input_line_pointer;
603       input_line_pointer = param;
604       val = get_absolute_expression ();
605       param = input_line_pointer;
606       input_line_pointer = save_ptr;
607
608       if (val >= 32)
609         {
610           as_warn ("Expression truncated to 5 bits");
611           val %= 32;
612         }
613     }
614
615   *valp = val << 21;
616   return param;
617 }
618
619 char *
620 get_cnd (param, valp)
621      char *param;
622      unsigned *valp;
623 {
624   unsigned int val;
625
626   if (isdigit (*param))
627     {
628       param = getval (param, &val);
629
630       if (val >= 32)
631         {
632           as_warn ("Expression truncated to 5 bits");
633           val %= 32;
634         }
635     }
636   else
637     {
638       if (isupper (*param))
639         *param = tolower (*param);
640
641       if (isupper (param[1]))
642         param[1] = tolower (param[1]);
643
644       param = match_name (param, cndmsk, valp);
645
646       if (param == NULL)
647         return NULL;
648
649       val = *valp;
650     }
651
652   *valp = val << 21;
653   return param;
654 }
655
656 char *
657 get_bf2 (param, bc)
658      char *param;
659      int bc;
660 {
661   int depth = 0;
662   int c;
663
664   for (;;)
665     {
666       c = *param;
667       if (c == 0)
668         return param;
669       else if (c == '(')
670         depth++;
671       else if (c == ')')
672         depth--;
673       else if (c == bc && depth <= 0)
674         return param;
675       param++;
676     }
677 }
678
679 char *
680 get_bf_offset_expression (param, offsetp)
681      char *param;
682      unsigned *offsetp;
683 {
684   unsigned offset;
685
686   if (isalpha (param[0]))
687     {
688       if (isupper (param[0]))
689         param[0] = tolower (param[0]);
690       if (isupper (param[1]))
691         param[1] = tolower (param[1]);
692
693       param = match_name (param, cmpslot, offsetp);
694
695       return param;
696     }
697   else
698     {
699       input_line_pointer = param;
700       offset = get_absolute_expression ();
701       param = input_line_pointer;
702     }
703
704   *offsetp = offset;
705   return param;
706 }
707
708 char *
709 get_bf (param, valp)
710      char *param;
711      unsigned *valp;
712 {
713   unsigned offset = 0;
714   unsigned width = 0;
715   char *xp;
716   char *save_ptr;
717
718   xp = get_bf2 (param, '<');
719
720   save_ptr = input_line_pointer;
721   input_line_pointer = param;
722   if (*xp == 0)
723     {
724       /* We did not find '<'.  We have an offset (width implicitly 32).  */
725       param = get_bf_offset_expression (param, &offset);
726       if (param == NULL)
727         return NULL;
728       input_line_pointer = save_ptr;
729     }
730   else
731     {
732       *xp++ = 0;                /* Overwrite the '<' */
733       param = get_bf2 (xp, '>');
734       if (*param == 0)
735         return NULL;
736       *param++ = 0;             /* Overwrite the '>' */
737
738       width = get_absolute_expression ();
739       xp =  get_bf_offset_expression (xp, &offset);
740       input_line_pointer = save_ptr;
741
742       if (xp + 1 != param)
743         return NULL;
744     }
745
746   *valp = ((width % 32) << 5) | (offset % 32);
747
748   return param;
749 }
750
751 char *
752 get_cr (param, regnop)
753      char *param;
754      unsigned *regnop;
755 {
756   unsigned regno;
757   unsigned c;
758 /*  int i; FIXME remove this */
759 /*  int name_len; FIXME remove this */
760
761   if (!strncmp (param, "cr", 2))
762     {
763       param += 2;
764
765       regno = *param++ - '0';
766       if (regno < 10)
767         {
768           if (regno == 0)
769             {
770               *regnop = 0;
771               return param;
772             }
773           c = *param - '0';
774           if (c < 10)
775             {
776               regno = regno * 10 + c;
777               if (c < 64)
778                 {
779                   *regnop = regno;
780                   return param + 1;
781                 }
782             }
783           else
784             {
785               *regnop = regno;
786               return param;
787             }
788         }
789       return NULL;
790     }
791
792   param = match_name (param, cr_regs, regnop);
793
794   return param;
795 }
796
797 char *
798 get_fcr (param, regnop)
799      char *param;
800      unsigned *regnop;
801 {
802   unsigned regno;
803   unsigned c;
804 /*  int i; FIXME remove this */
805 /*  int name_len; FIXME: remove this */
806
807   if (!strncmp (param, "fcr", 3))
808     {
809       param += 3;
810
811       regno = *param++ - '0';
812       if (regno < 10)
813         {
814           if (regno == 0)
815             {
816               *regnop = 0;
817               return param;
818             }
819           c = *param - '0';
820           if (c < 10)
821             {
822               regno = regno * 10 + c;
823               if (c < 64)
824                 {
825                   *regnop = regno;
826                   return param + 1;
827                 }
828             }
829           else
830             {
831               *regnop = regno;
832               return param;
833             }
834         }
835       return NULL;
836     }
837
838   param = match_name (param, fcr_regs, regnop);
839
840   return param;
841 }
842
843 char *
844 get_vec9 (param, valp)
845      char *param;
846      unsigned *valp;
847 {
848   unsigned val;
849   char *save_ptr;
850
851   save_ptr = input_line_pointer;
852   input_line_pointer = param;
853   val = get_absolute_expression ();
854   param = input_line_pointer;
855   input_line_pointer = save_ptr;
856
857   if (val >= 1 << 9)
858     as_warn ("Expression truncated to 9 bits");
859
860   *valp = val % (1 << 9);
861
862   return param;
863 }
864
865 #define hexval(z) \
866   (isdigit (z) ? (z) - '0' :                                            \
867    islower (z) ? (z) - 'a' + 10 :                                       \
868    isupper (z) ? (z) - 'A' + 10 : -1)
869
870 char *
871 getval (param, valp)
872      char *param;
873      unsigned int *valp;
874 {
875   unsigned int val = 0;
876   unsigned int c;
877
878   c = *param++;
879   if (c == '0')
880     {
881       c = *param++;
882       if (c == 'x' || c == 'X')
883         {
884           c = *param++;
885           c = hexval (c);
886           while (c < 16)
887             {
888               val = val * 16 + c;
889               c = *param++;
890               c = hexval (c);
891             }
892         }
893       else
894         {
895           c -= '0';
896           while (c < 8)
897             {
898               val = val * 8 + c;
899               c = *param++ - '0';
900             }
901         }
902     }
903   else
904     {
905       c -= '0';
906       while (c < 10)
907         {
908           val = val * 10 + c;
909           c = *param++ - '0';
910         }
911     }
912
913   *valp = val;
914   return param - 1;
915 }
916
917 void
918 md_number_to_chars (buf, val, nbytes)
919 char *buf;
920 long val;
921 int nbytes;
922 {
923   switch (nbytes)
924     {
925     case 4:
926       *buf++ = val >> 24;
927       *buf++ = val >> 16;
928     case 2:
929       *buf++ = val >> 8;
930     case 1:
931       *buf = val;
932       break;
933
934     default:
935       abort ();
936     }
937 }
938
939 #ifdef comment
940
941 void
942 md_number_to_imm (buf, val, nbytes, fixP, seg_type)
943 unsigned char *buf;
944 unsigned int val;
945 int nbytes;
946 fixS *fixP;
947 int seg_type;
948 {
949   if (seg_type != N_TEXT || fixP->fx_r_type == NO_RELOC)
950     {
951       switch (nbytes)
952         {
953         case 4:
954           *buf++ = val >> 24;
955           *buf++ = val >> 16;
956         case 2:
957           *buf++ = val >> 8;
958         case 1:
959           *buf = val;
960           break;
961
962         default:
963           abort ();
964         }
965       return;
966     }
967
968   switch (fixP->fx_r_type)
969     {
970     case RELOC_IW16:
971       buf[2] = val >> 8;
972       buf[3] = val;
973       break;
974
975     case RELOC_LO16:
976       buf[0] = val >> 8;
977       buf[1] = val;
978       break;
979
980     case RELOC_HI16:
981       buf[0] = val >> 24;
982       buf[1] = val >> 16;
983       break;
984
985     case RELOC_PC16:
986       val += 4;
987       buf[0] = val >> 10;
988       buf[1] = val >> 2;
989       break;
990
991     case RELOC_PC26:
992       val += 4;
993       buf[0] |= (val >> 26) & 0x03;
994       buf[1] = val >> 18;
995       buf[2] = val >> 10;
996       buf[3] = val >> 2;
997       break;
998
999     case RELOC_32:
1000       buf[0] = val >> 24;
1001       buf[1] = val >> 16;
1002       buf[2] = val >> 8;
1003       buf[3] = val;
1004       break;
1005
1006     default:
1007       as_fatal ("Bad relocation type");
1008       break;
1009     }
1010 }
1011 #endif /* comment */
1012
1013 /* Apply a fixS to the frags, now that we know the value it ought to
1014    hold. */
1015
1016 void md_apply_fix(fixP, val)
1017 fixS *fixP;
1018 long val;
1019 {
1020         char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1021
1022         fixP->fx_addnumber = val;
1023
1024
1025         switch (fixP->fx_r_type) {
1026
1027         case RELOC_IW16:
1028                 buf[2] = val >> 8;
1029                 buf[3] = val;
1030                 break;
1031
1032         case RELOC_LO16:
1033                 buf[0] = val >> 8;
1034                 buf[1] = val;
1035                 break;
1036
1037         case RELOC_HI16:
1038                 buf[0] = val >> 24;
1039                 buf[1] = val >> 16;
1040                 break;
1041
1042         case RELOC_PC16:
1043                 val += 4;
1044                 buf[0] = val >> 10;
1045                 buf[1] = val >> 2;
1046                 break;
1047
1048         case RELOC_PC26:
1049                 val += 4;
1050                 buf[0] |= (val >> 26) & 0x03;
1051                 buf[1] = val >> 18;
1052                 buf[2] = val >> 10;
1053                 buf[3] = val >> 2;
1054                 break;
1055
1056         case RELOC_32:
1057                 buf[0] = val >> 24;
1058                 buf[1] = val >> 16;
1059                 buf[2] = val >> 8;
1060                 buf[3] = val;
1061                 break;
1062
1063         case NO_RELOC:
1064                 switch (fixP->fx_size) {
1065                 case 4:
1066                         *buf++ = val >> 24;
1067                         *buf++ = val >> 16;
1068                 case 2:
1069                         *buf++ = val >> 8;
1070                 case 1:
1071                         *buf = val;
1072                         break;
1073
1074                 default:
1075                         abort ();
1076                 }
1077
1078         default:
1079                 as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
1080                 break;
1081         }
1082
1083         return;
1084 } /* md_apply_fix() */
1085
1086 void
1087 md_number_to_disp (buf, val, nbytes)
1088 char *buf;
1089 int val;
1090 int nbytes;
1091 {
1092   as_fatal ("md_number_to_disp not defined");
1093   md_number_to_chars (buf, val, nbytes);
1094 }
1095
1096 void
1097 md_number_to_field (buf, val, nbytes)
1098 char *buf;
1099 int val;
1100 int nbytes;
1101 {
1102   as_fatal ("md_number_to_field not defined");
1103   md_number_to_chars (buf, val, nbytes);
1104 }
1105
1106 #define MAX_LITTLENUMS 6
1107
1108 /* Turn a string in input_line_pointer into a floating point constant of type
1109    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
1110    emitted is stored in *sizeP. An error message is returned, or NULL on OK.
1111  */
1112 char *
1113 md_atof (type, litP, sizeP)
1114      char type;
1115      char *litP;
1116      int *sizeP;
1117 {
1118   int   prec;
1119   LITTLENUM_TYPE words[MAX_LITTLENUMS];
1120   LITTLENUM_TYPE *wordP;
1121   char  *t;
1122   char  *atof_ieee ();
1123
1124   switch (type)
1125     {
1126     case 'f':
1127     case 'F':
1128     case 's':
1129     case 'S':
1130       prec = 2;
1131       break;
1132
1133     case 'd':
1134     case 'D':
1135     case 'r':
1136     case 'R':
1137       prec = 4;
1138       break;
1139
1140     case 'x':
1141     case 'X':
1142       prec = 6;
1143       break;
1144
1145     case 'p':
1146     case 'P':
1147       prec = 6;
1148       break;
1149
1150     default:
1151       *sizeP=0;
1152       return "Bad call to MD_ATOF()";
1153     }
1154   t=atof_ieee (input_line_pointer, type, words);
1155   if (t)
1156     input_line_pointer=t;
1157
1158   *sizeP=prec * sizeof (LITTLENUM_TYPE);
1159   for (wordP=words;prec--;)
1160     {
1161       md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
1162       litP+=sizeof (LITTLENUM_TYPE);
1163     }
1164   return "";    /* Someone should teach Dean about null pointers */
1165 }
1166
1167 int md_short_jump_size = 4;
1168
1169 void
1170 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
1171      char *ptr;
1172      long from_addr, to_addr;
1173      fragS *frag;
1174      symbolS *to_symbol;
1175 {
1176   ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00;
1177   fix_new (frag,
1178            ptr - frag->fr_literal,
1179            4,
1180            to_symbol,
1181            (symbolS *) 0,
1182            (long int) 0,
1183            0,
1184            RELOC_PC26);         /* Botch: Shouldn't this be RELOC_PC16? */
1185 }
1186
1187 int md_long_jump_size = 4;
1188
1189 void
1190 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
1191      char *ptr;
1192      long from_addr, to_addr;
1193      fragS *frag;
1194      symbolS *to_symbol;
1195 {
1196   ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00;
1197   fix_new (frag,
1198            ptr - frag->fr_literal,
1199            4,
1200            to_symbol,
1201            (symbolS *) 0,
1202            (long int) 0,
1203            0,
1204            RELOC_PC26);
1205 }
1206
1207 int
1208 md_estimate_size_before_relax (fragP, segment_type)
1209      fragS *fragP;
1210      segT segment_type;
1211 {
1212         as_fatal("Relaxation should never occur");
1213         return(0);
1214 }
1215
1216 const relax_typeS md_relax_table[] = {0};
1217
1218 void
1219 md_convert_frag (headers, fragP)
1220 object_headers *headers;
1221      fragS *fragP;
1222 {
1223   as_fatal ("Relaxation should never occur");
1224 }
1225
1226 void
1227 md_end ()
1228 {
1229 }
1230
1231 #ifdef comment
1232
1233 /*
1234  * Risc relocations are completely different, so it needs
1235  * this machine dependent routine to emit them.
1236  */
1237 void
1238 emit_relocations (fixP, segment_address_in_file)
1239     fixS *fixP;
1240     relax_addressT segment_address_in_file;
1241 {
1242     struct reloc_info_m88k ri;
1243     symbolS *symbolP;
1244     extern char *next_object_file_charP;
1245
1246     bzero ((char *) &ri, sizeof (ri));
1247     for (; fixP; fixP = fixP->fx_next) {
1248
1249         if (fixP->fx_r_type >= NO_RELOC) {
1250             fprintf (stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
1251             abort ();
1252         }
1253
1254         if ((symbolP = fixP->fx_addsy) != NULL) {
1255             ri.r_address = fixP->fx_frag->fr_address +
1256                 fixP->fx_where - segment_address_in_file;
1257             if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
1258                 ri.r_extern = 1;
1259                 ri.r_symbolnum = symbolP->sy_number;
1260             } else {
1261                 ri.r_extern = 0;
1262                 ri.r_symbolnum = symbolP->sy_type & N_TYPE;
1263             }
1264             if (symbolP && symbolP->sy_frag) {
1265                 ri.r_addend = symbolP->sy_frag->fr_address;
1266             }
1267             ri.r_type = fixP->fx_r_type;
1268             if (fixP->fx_pcrel) {
1269 /*              ri.r_addend -= fixP->fx_where;          */
1270                 ri.r_addend -= ri.r_address;
1271             } else {
1272                 ri.r_addend = fixP->fx_addnumber;
1273             }
1274
1275 /*          md_ri_to_chars ((char *) &ri, ri);        */
1276             append (&next_object_file_charP, (char *)& ri, sizeof (ri));
1277         }
1278     }
1279     return;
1280 }
1281 #endif /* comment */
1282
1283 /* Translate internal representation of relocation info to target format.
1284
1285    On m88k: first 4 bytes are normal unsigned long address,
1286    next three bytes are index, most sig. byte first.
1287    Byte 7 is broken up with bit 7 as external,
1288         bits 6, 5, & 4 unused, and the lower four bits as relocation
1289         type.
1290    Next 4 bytes are long addend. */
1291
1292 void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
1293 char *where;
1294 fixS *fixP;
1295 relax_addressT segment_address_in_file;
1296 {
1297         long r_index;
1298         long r_extern;
1299         long r_addend = 0;
1300         long r_address;
1301
1302         know(fixP->fx_addsy);
1303
1304         if (!S_IS_DEFINED(fixP->fx_addsy)) {
1305                 r_extern = 1;
1306                 r_index = fixP->fx_addsy->sy_number;
1307         } else {
1308                 r_extern = 0;
1309                 r_index = S_GET_TYPE(fixP->fx_addsy);
1310         }
1311
1312         /* this is easy */
1313         md_number_to_chars(where,
1314                            r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
1315                            4);
1316
1317         /* now the fun stuff */
1318         where[4] = (r_index >> 16) & 0x0ff;
1319         where[5] = (r_index >> 8) & 0x0ff;
1320         where[6] = r_index & 0x0ff;
1321         where[7] = ((r_extern << 7)  & 0x80) | (0 & 0x70) | (fixP->fx_r_type & 0xf);
1322
1323         /* Also easy */
1324         if (fixP->fx_addsy->sy_frag) {
1325                 r_addend = fixP->fx_addsy->sy_frag->fr_address;
1326         }
1327
1328         if (fixP->fx_pcrel) {
1329                 r_addend -= r_address;
1330         } else {
1331                 r_addend = fixP->fx_addnumber;
1332         }
1333
1334         md_number_to_chars(&where[8], r_addend, 4);
1335
1336         return;
1337 } /* tc_aout_fix_to_chars() */
1338
1339
1340 static void
1341 s_bss()
1342 {
1343   char *name;
1344   char c;
1345   char *p;
1346   int temp, bss_align = 1;
1347   symbolS *symbolP;
1348   extern char is_end_of_line[256];
1349
1350   name = input_line_pointer;
1351   c = get_symbol_end();
1352   p = input_line_pointer;
1353   *p = c;
1354   SKIP_WHITESPACE();
1355   if ( * input_line_pointer != ',' )
1356     {
1357       as_warn("Expected comma after name");
1358       ignore_rest_of_line();
1359       return;
1360     }
1361   input_line_pointer ++;
1362   if ((temp = get_absolute_expression()) < 0)
1363     {
1364       as_warn("BSS length (%d.) <0! Ignored.", temp);
1365       ignore_rest_of_line();
1366       return;
1367     }
1368   *p = 0;
1369   symbolP = symbol_find_or_make(name);
1370   *p = c;
1371   if (*input_line_pointer == ',')
1372     {
1373       input_line_pointer++;
1374       bss_align = get_absolute_expression();
1375       while (local_bss_counter % bss_align != 0)
1376         local_bss_counter++;
1377     }
1378
1379   if (!S_IS_DEFINED(symbolP)
1380       || (S_GET_SEGMENT(symbolP) == SEG_BSS
1381           && S_GET_VALUE(symbolP) == local_bss_counter)) {
1382           S_SET_VALUE(symbolP, local_bss_counter);
1383           S_SET_SEGMENT(symbolP, SEG_BSS);
1384           symbolP->sy_frag  = &bss_address_frag;
1385           local_bss_counter += temp;
1386   } else {
1387           as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
1388                   S_GET_VALUE(symbolP), local_bss_counter );
1389   }
1390   while (!is_end_of_line[*input_line_pointer])
1391     {
1392       input_line_pointer++;
1393     }
1394
1395   return;
1396 }
1397
1398 /* We have no need to default values of symbols. */
1399
1400 /* ARGSUSED */
1401 symbolS *md_undefined_symbol(name)
1402 char *name;
1403 {
1404         return 0;
1405 } /* md_undefined_symbol() */
1406
1407 /* Parse an operand that is machine-specific.
1408    We just return without modifying the expression if we have nothing
1409    to do. */
1410
1411 /* ARGSUSED */
1412 void md_operand(expressionP)
1413 expressionS *expressionP;
1414 {
1415 } /* md_operand() */
1416
1417 /* Round up a section size to the appropriate boundary. */
1418 long md_section_align(segment, size)
1419 segT segment;
1420 long size;
1421 {
1422         return((size + 7) & ~7); /* Round all sects to multiple of 8 */
1423 } /* md_section_align() */
1424
1425 /* Exactly what point is a PC-relative offset relative TO?
1426    On the sparc, they're relative to the address of the offset, plus
1427    its size.  This gets us to the following instruction.
1428    (??? Is this right?  FIXME-SOON) */
1429 long md_pcrel_from(fixP)
1430 fixS *fixP;
1431 {
1432         return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
1433 } /* md_pcrel_from() */
1434
1435  /* end of tc-m88k.c */