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 
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 
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 
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 
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 
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 }
641