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