]> Git Repo - binutils.git/blob - gas/config/tc-fr30.c
* config/tc-i960.c (line_comment_chars): Add '#'.
[binutils.git] / gas / config / tc-fr30.c
1 /* tc-fr30.c -- Assembler for the Fujitsu FR30.
2    Copyright 1998, 1999, 2000, 2001, 2002, 2003
3    Free Software Foundation, Inc.
4
5    This file is part of GAS, the GNU Assembler.
6
7    GAS is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11
12    GAS is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GAS; see the file COPYING.  If not, write to
19    the Free Software Foundation, 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 #include <stdio.h>
23 #include "as.h"
24 #include "safe-ctype.h"
25 #include "subsegs.h"
26 #include "symcat.h"
27 #include "opcodes/fr30-desc.h"
28 #include "opcodes/fr30-opc.h"
29 #include "cgen.h"
30
31 /* Structure to hold all of the different components describing
32    an individual instruction.  */
33 typedef struct
34 {
35   const CGEN_INSN *     insn;
36   const CGEN_INSN *     orig_insn;
37   CGEN_FIELDS           fields;
38 #if CGEN_INT_INSN_P
39   CGEN_INSN_INT         buffer [1];
40 #define INSN_VALUE(buf) (*(buf))
41 #else
42   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
43 #define INSN_VALUE(buf) (buf)
44 #endif
45   char *                addr;
46   fragS *               frag;
47   int                   num_fixups;
48   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
49   int                   indices [MAX_OPERAND_INSTANCES];
50 }
51 fr30_insn;
52
53 const char comment_chars[]        = ";";
54 const char line_comment_chars[]   = "#";
55 const char line_separator_chars[] = "|";
56 const char EXP_CHARS[]            = "eE";
57 const char FLT_CHARS[]            = "dD";
58 \f
59 #define FR30_SHORTOPTS ""
60 const char * md_shortopts = FR30_SHORTOPTS;
61
62 struct option md_longopts[] =
63 {
64   {NULL, no_argument, NULL, 0}
65 };
66 size_t md_longopts_size = sizeof (md_longopts);
67
68 int
69 md_parse_option (c, arg)
70      int c ATTRIBUTE_UNUSED;
71      char *arg ATTRIBUTE_UNUSED;
72 {
73   switch (c)
74     {
75     default:
76       return 0;
77     }
78   return 1;
79 }
80
81 void
82 md_show_usage (stream)
83   FILE * stream;
84 {
85   fprintf (stream, _(" FR30 specific command line options:\n"));
86 }
87
88 /* The target specific pseudo-ops which we support.  */
89 const pseudo_typeS md_pseudo_table[] =
90 {
91   { "word",     cons,           4 },
92   { NULL,       NULL,           0 }
93 };
94
95 \f
96 void
97 md_begin ()
98 {
99   /* Initialize the `cgen' interface.  */
100
101   /* Set the machine number and endian.  */
102   gas_cgen_cpu_desc = fr30_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
103                                           CGEN_CPU_OPEN_ENDIAN,
104                                           CGEN_ENDIAN_BIG,
105                                           CGEN_CPU_OPEN_END);
106   fr30_cgen_init_asm (gas_cgen_cpu_desc);
107
108   /* This is a callback from cgen to gas to parse operands.  */
109   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
110 }
111
112 void
113 md_assemble (str)
114      char *str;
115 {
116   static int last_insn_had_delay_slot = 0;
117   fr30_insn insn;
118   char *errmsg;
119
120   /* Initialize GAS's cgen interface for a new instruction.  */
121   gas_cgen_init_parse ();
122
123   insn.insn = fr30_cgen_assemble_insn
124     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
125
126   if (!insn.insn)
127     {
128       as_bad (errmsg);
129       return;
130     }
131
132   /* Doesn't really matter what we pass for RELAX_P here.  */
133   gas_cgen_finish_insn (insn.insn, insn.buffer,
134                         CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
135
136   /* Warn about invalid insns in delay slots.  */
137   if (last_insn_had_delay_slot
138       && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_NOT_IN_DELAY_SLOT))
139     as_warn (_("Instruction %s not allowed in a delay slot."),
140              CGEN_INSN_NAME (insn.insn));
141
142   last_insn_had_delay_slot
143     = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
144 }
145
146 /* The syntax in the manual says constants begin with '#'.
147    We just ignore it.  */
148
149 void
150 md_operand (expressionP)
151      expressionS * expressionP;
152 {
153   if (* input_line_pointer == '#')
154     {
155       input_line_pointer ++;
156       expression (expressionP);
157     }
158 }
159
160 valueT
161 md_section_align (segment, size)
162      segT   segment;
163      valueT size;
164 {
165   int align = bfd_get_section_alignment (stdoutput, segment);
166   return ((size + (1 << align) - 1) & (-1 << align));
167 }
168
169 symbolS *
170 md_undefined_symbol (name)
171   char *name ATTRIBUTE_UNUSED;
172 {
173   return 0;
174 }
175 \f
176 /* Interface to relax_segment.  */
177
178 /* FIXME: Build table by hand, get it working, then machine generate.  */
179
180 const relax_typeS md_relax_table[] =
181 {
182 /* The fields are:
183    1) most positive reach of this state,
184    2) most negative reach of this state,
185    3) how many bytes this mode will add to the size of the current frag
186    4) which index into the table to try if we can't fit into this one.  */
187
188   /* The first entry must be unused because an `rlx_more' value of zero ends
189      each list.  */
190   {1, 1, 0, 0},
191
192   /* The displacement used by GAS is from the end of the 2 byte insn,
193      so we subtract 2 from the following.  */
194   /* 16 bit insn, 8 bit disp -> 10 bit range.
195      This doesn't handle a branch in the right slot at the border:
196      the "& -4" isn't taken into account.  It's not important enough to
197      complicate things over it, so we subtract an extra 2 (or + 2 in -ve
198      case).  */
199   {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
200   /* 32 bit insn, 24 bit disp -> 26 bit range.  */
201   {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
202   /* Same thing, but with leading nop for alignment.  */
203   {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
204 };
205
206 #if 0
207 long
208 fr30_relax_frag (segment, fragP, stretch)
209      segT    segment;
210      fragS * fragP;
211      long    stretch;
212 {
213   /* Address of branch insn.  */
214   long address = fragP->fr_address + fragP->fr_fix - 2;
215   long growth = 0;
216
217   /* Keep 32 bit insns aligned on 32 bit boundaries.  */
218   if (fragP->fr_subtype == 2)
219     {
220       if ((address & 3) != 0)
221         {
222           fragP->fr_subtype = 3;
223           growth = 2;
224         }
225     }
226   else if (fragP->fr_subtype == 3)
227     {
228       if ((address & 3) == 0)
229         {
230           fragP->fr_subtype = 2;
231           growth = -2;
232         }
233     }
234   else
235     {
236       growth = relax_frag (segment, fragP, stretch);
237
238       /* Long jump on odd halfword boundary?  */
239       if (fragP->fr_subtype == 2 && (address & 3) != 0)
240         {
241           fragP->fr_subtype = 3;
242           growth += 2;
243         }
244     }
245
246   return growth;
247 }
248 #endif
249
250 /* Return an initial guess of the length by which a fragment must grow to
251    hold a branch to reach its destination.
252    Also updates fr_type/fr_subtype as necessary.
253
254    Called just before doing relaxation.
255    Any symbol that is now undefined will not become defined.
256    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
257    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
258    Although it may not be explicit in the frag, pretend fr_var starts with a
259    0 value.  */
260
261 int
262 md_estimate_size_before_relax (fragP, segment)
263      fragS * fragP;
264      segT    segment;
265 {
266   /* The only thing we have to handle here are symbols outside of the
267      current segment.  They may be undefined or in a different segment in
268      which case linker scripts may place them anywhere.
269      However, we can't finish the fragment here and emit the reloc as insn
270      alignment requirements may move the insn about.  */
271
272   if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
273     {
274 #if 0
275       int    old_fr_fix = fragP->fr_fix;
276 #endif
277
278       /* The symbol is undefined in this segment.
279          Change the relaxation subtype to the max allowable and leave
280          all further handling to md_convert_frag.  */
281       fragP->fr_subtype = 2;
282
283 #if 0 /* Can't use this, but leave in for illustration.  */
284       /* Change 16 bit insn to 32 bit insn.  */
285       fragP->fr_opcode[0] |= 0x80;
286
287       /* Increase known (fixed) size of fragment.  */
288       fragP->fr_fix += 2;
289
290       /* Create a relocation for it.  */
291       fix_new (fragP, old_fr_fix, 4,
292                fragP->fr_symbol,
293                fragP->fr_offset, 1 /* pcrel */,
294                /* FIXME: Can't use a real BFD reloc here.
295                   gas_cgen_md_apply_fix3 can't handle it.  */
296                BFD_RELOC_FR30_26_PCREL);
297
298       /* Mark this fragment as finished.  */
299       frag_wane (fragP);
300       return fragP->fr_fix - old_fr_fix;
301 #else
302       {
303         const CGEN_INSN * insn;
304         int               i;
305
306         /* Update the recorded insn.
307            Fortunately we don't have to look very far.
308            FIXME: Change this to record in the instruction the next higher
309            relaxable insn to use.  */
310         for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
311           {
312             if ((strcmp (CGEN_INSN_MNEMONIC (insn),
313                          CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
314                  == 0)
315                 && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
316               break;
317           }
318         if (i == 4)
319           abort ();
320
321         fragP->fr_cgen.insn = insn;
322         return 2;
323       }
324 #endif
325     }
326
327   /* Return the size of the variable part of the frag.  */
328   return md_relax_table[fragP->fr_subtype].rlx_length;
329 }
330
331 /* *fragP has been relaxed to its final size, and now needs to have
332    the bytes inside it modified to conform to the new size.
333
334    Called after relaxation is finished.
335    fragP->fr_type == rs_machine_dependent.
336    fragP->fr_subtype is the subtype of what the address relaxed to.  */
337
338 void
339 md_convert_frag (abfd, sec, fragP)
340   bfd *abfd ATTRIBUTE_UNUSED;
341   segT sec ATTRIBUTE_UNUSED;
342   fragS *fragP ATTRIBUTE_UNUSED;
343 {
344 #if 0
345   char * opcode;
346   char * displacement;
347   int    target_address;
348   int    opcode_address;
349   int    extension;
350   int    addend;
351
352   opcode = fragP->fr_opcode;
353
354   /* Address opcode resides at in file space.  */
355   opcode_address = fragP->fr_address + fragP->fr_fix - 2;
356
357   switch (fragP->fr_subtype)
358     {
359     case 1 :
360       extension = 0;
361       displacement = & opcode[1];
362       break;
363     case 2 :
364       opcode[0] |= 0x80;
365       extension = 2;
366       displacement = & opcode[1];
367       break;
368     case 3 :
369       opcode[2] = opcode[0] | 0x80;
370       md_number_to_chars (opcode, PAR_NOP_INSN, 2);
371       opcode_address += 2;
372       extension = 4;
373       displacement = & opcode[3];
374       break;
375     default :
376       abort ();
377     }
378
379   if (S_GET_SEGMENT (fragP->fr_symbol) != sec)
380     {
381       /* symbol must be resolved by linker */
382       if (fragP->fr_offset & 3)
383         as_warn (_("Addend to unresolved symbol not on word boundary."));
384       addend = fragP->fr_offset >> 2;
385     }
386   else
387     {
388       /* Address we want to reach in file space.  */
389       target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
390       addend = (target_address - (opcode_address & -4)) >> 2;
391     }
392
393   /* Create a relocation for symbols that must be resolved by the linker.
394      Otherwise output the completed insn.  */
395
396   if (S_GET_SEGMENT (fragP->fr_symbol) != sec)
397     {
398       assert (fragP->fr_subtype != 1);
399       assert (fragP->fr_cgen.insn != 0);
400       gas_cgen_record_fixup (fragP,
401                              /* Offset of branch insn in frag.  */
402                              fragP->fr_fix + extension - 4,
403                              fragP->fr_cgen.insn,
404                              4 /*length*/,
405                              /* FIXME: quick hack */
406 #if 0
407                              CGEN_OPERAND_ENTRY (fragP->fr_cgen.opindex),
408 #else
409                              CGEN_OPERAND_ENTRY (FR30_OPERAND_DISP24),
410 #endif
411                              fragP->fr_cgen.opinfo,
412                              fragP->fr_symbol, fragP->fr_offset);
413     }
414
415 #define SIZE_FROM_RELAX_STATE(n) ((n) == 1 ? 1 : 3)
416
417   md_number_to_chars (displacement, (valueT) addend,
418                       SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
419
420   fragP->fr_fix += extension;
421 #endif
422 }
423 \f
424 /* Functions concerning relocs.  */
425
426 /* The location from which a PC relative jump should be calculated,
427    given a PC relative reloc.  */
428
429 long
430 md_pcrel_from_section (fixP, sec)
431      fixS * fixP;
432      segT   sec;
433 {
434   if (fixP->fx_addsy != (symbolS *) NULL
435       && (! S_IS_DEFINED (fixP->fx_addsy)
436           || S_GET_SEGMENT (fixP->fx_addsy) != sec))
437     {
438       /* The symbol is undefined (or is defined but not in this section).
439          Let the linker figure it out.  */
440       return 0;
441     }
442
443   return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
444 }
445
446 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
447    Returns BFD_RELOC_NONE if no reloc type can be found.
448    *FIXP may be modified if desired.  */
449
450 bfd_reloc_code_real_type
451 md_cgen_lookup_reloc (insn, operand, fixP)
452      const CGEN_INSN *insn ATTRIBUTE_UNUSED;
453      const CGEN_OPERAND *operand;
454      fixS *fixP;
455 {
456   switch (operand->type)
457     {
458     case FR30_OPERAND_LABEL9:  fixP->fx_pcrel = 1; return BFD_RELOC_FR30_9_PCREL;
459     case FR30_OPERAND_LABEL12: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_12_PCREL;
460     case FR30_OPERAND_DISP10:  return BFD_RELOC_FR30_10_IN_8;
461     case FR30_OPERAND_DISP9:   return BFD_RELOC_FR30_9_IN_8;
462     case FR30_OPERAND_DISP8:   return BFD_RELOC_FR30_8_IN_8;
463     case FR30_OPERAND_UDISP6:  return BFD_RELOC_FR30_6_IN_4;
464     case FR30_OPERAND_I8:      return BFD_RELOC_8;
465     case FR30_OPERAND_I32:     return BFD_RELOC_FR30_48;
466     case FR30_OPERAND_I20:     return BFD_RELOC_FR30_20;
467     default : /* avoid -Wall warning */
468       break;
469     }
470
471   return BFD_RELOC_NONE;
472 }
473 \f
474 /* Write a value out to the object file, using the appropriate endianness.  */
475
476 void
477 md_number_to_chars (buf, val, n)
478      char * buf;
479      valueT val;
480      int    n;
481 {
482   number_to_chars_bigendian (buf, val, n);
483 }
484
485 /* Turn a string in input_line_pointer into a floating point constant of type
486    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
487    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
488 */
489
490 /* Equal to MAX_PRECISION in atof-ieee.c */
491 #define MAX_LITTLENUMS 6
492
493 char *
494 md_atof (type, litP, sizeP)
495      char   type;
496      char * litP;
497      int *  sizeP;
498 {
499   int              i;
500   int              prec;
501   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
502   char *           t;
503
504   switch (type)
505     {
506     case 'f':
507     case 'F':
508     case 's':
509     case 'S':
510       prec = 2;
511       break;
512
513     case 'd':
514     case 'D':
515     case 'r':
516     case 'R':
517       prec = 4;
518       break;
519
520    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
521
522     default:
523       * sizeP = 0;
524       return _("Bad call to md_atof()");
525     }
526
527   t = atof_ieee (input_line_pointer, type, words);
528   if (t)
529     input_line_pointer = t;
530   * sizeP = prec * sizeof (LITTLENUM_TYPE);
531
532   for (i = 0; i < prec; i++)
533     {
534       md_number_to_chars (litP, (valueT) words[i],
535                           sizeof (LITTLENUM_TYPE));
536       litP += sizeof (LITTLENUM_TYPE);
537     }
538
539   return 0;
540 }
541
542 /* Worker function for fr30_is_colon_insn().  */
543 static char restore_colon PARAMS ((int));
544
545 static char
546 restore_colon (advance_i_l_p_by)
547      int advance_i_l_p_by;
548 {
549   char c;
550
551   /* Restore the colon, and advance input_line_pointer to
552      the end of the new symbol.  */
553   * input_line_pointer = ':';
554   input_line_pointer += advance_i_l_p_by;
555   c = * input_line_pointer;
556   * input_line_pointer = 0;
557
558   return c;
559 }
560
561 /* Determines if the symbol starting at START and ending in
562    a colon that was at the location pointed to by INPUT_LINE_POINTER
563    (but which has now been replaced bu a NUL) is in fact an
564    LDI:8, LDI:20, LDI:32, CALL:D. JMP:D, RET:D or Bcc:D instruction.
565    If it is, then it restores the colon, advances INPUT_LINE_POINTER
566    to the real end of the instruction/symbol, and returns the character
567    that really terminated the symbol.  Otherwise it returns 0.  */
568 char
569 fr30_is_colon_insn (start)
570      char *  start;
571 {
572   char * i_l_p = input_line_pointer;
573
574   /* Check to see if the symbol parsed so far is 'ldi'  */
575   if (   (start[0] != 'l' && start[0] != 'L')
576       || (start[1] != 'd' && start[1] != 'D')
577       || (start[2] != 'i' && start[2] != 'I')
578       || start[3] != 0)
579     {
580       /* Nope - check to see a 'd' follows the colon.  */
581       if (   (i_l_p[1] == 'd' || i_l_p[1] == 'D')
582           && (i_l_p[2] == ' ' || i_l_p[2] == '\t' || i_l_p[2] == '\n'))
583         {
584           /* Yup - it might be delay slot instruction.  */
585           int           i;
586           static char * delay_insns [] =
587           {
588             "call", "jmp", "ret", "bra", "bno",
589             "beq",  "bne", "bc",  "bnc", "bn",
590             "bp",   "bv",  "bnv", "blt", "bge",
591             "ble",  "bgt", "bls", "bhi"
592           };
593
594           for (i = sizeof (delay_insns) / sizeof (delay_insns[0]); i--;)
595             {
596               char * insn = delay_insns[i];
597               int    len  = strlen (insn);
598
599               if (start [len] != 0)
600                 continue;
601
602               while (len --)
603                 if (TOLOWER (start [len]) != insn [len])
604                   break;
605
606               if (len == -1)
607                 return restore_colon (1);
608             }
609         }
610
611       /* Nope - it is a normal label.  */
612       return 0;
613     }
614
615   /* Check to see if the text following the colon is '8' */
616   if (i_l_p[1] == '8' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
617     return restore_colon (2);
618
619   /* Check to see if the text following the colon is '20' */
620   else if (i_l_p[1] == '2' && i_l_p[2] =='0' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
621     return restore_colon (3);
622
623   /* Check to see if the text following the colon is '32' */
624   else if (i_l_p[1] == '3' && i_l_p[2] =='2' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
625     return restore_colon (3);
626
627   return 0;
628 }
629
630 bfd_boolean
631 fr30_fix_adjustable (fixP)
632    fixS * fixP;
633 {
634   /* We need the symbol name for the VTABLE entries */
635   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
636       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
637     return 0;
638
639   return 1;
640 }
This page took 0.060753 seconds and 4 git commands to generate.