Add fr450 support.
[external/binutils.git] / gas / config / tc-frv.c
1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2    Copyright 2002, 2003 Free Software Foundation.
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 "subsegs.h"     
24 #include "symcat.h"
25 #include "opcodes/frv-desc.h"
26 #include "opcodes/frv-opc.h"
27 #include "cgen.h"
28 #include "libbfd.h"
29 #include "elf/common.h"
30 #include "elf/frv.h"
31
32 /* Structure to hold all of the different components describing
33    an individual instruction.  */
34 typedef struct
35 {
36   const CGEN_INSN *     insn;
37   const CGEN_INSN *     orig_insn;
38   CGEN_FIELDS           fields;
39 #if CGEN_INT_INSN_P
40   CGEN_INSN_INT         buffer [1];
41 #define INSN_VALUE(buf) (*(buf))
42 #else
43   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
44 #define INSN_VALUE(buf) (buf)
45 #endif
46   char *                addr;
47   fragS *               frag;
48   int                   num_fixups;
49   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
50   int                   indices [MAX_OPERAND_INSTANCES];
51 }
52 frv_insn;
53
54 enum vliw_insn_type
55 {
56   VLIW_GENERIC_TYPE,            /* Don't care about this insn.  */
57   VLIW_BRANCH_TYPE,             /* A Branch.  */
58   VLIW_LABEL_TYPE,              /* A Label.  */
59   VLIW_NOP_TYPE,                /* A NOP.  */
60   VLIW_BRANCH_HAS_NOPS          /* A Branch that requires NOPS.  */
61 };
62
63 /* We're going to use these in the fr_subtype field to mark 
64    whether to keep inserted nops.  */
65
66 #define NOP_KEEP 1              /* Keep these NOPS.  */
67 #define NOP_DELETE 2            /* Delete these NOPS.  */
68
69 #define DO_COUNT    TRUE
70 #define DONT_COUNT  FALSE
71
72 /* A list of insns within a VLIW insn.  */
73 struct vliw_insn_list
74 {
75   /*  The type of this insn.  */
76   enum vliw_insn_type   type;
77
78   /*  The corresponding gas insn information.  */
79   const CGEN_INSN       *insn;
80
81   /*  For branches and labels, the symbol that is referenced.  */
82   symbolS               *sym;
83
84   /*  For branches, the frag containing the single nop that was generated.  */
85   fragS                 *snop_frag;
86
87   /*  For branches, the frag containing the double nop that was generated.  */
88   fragS                 *dnop_frag;
89
90   /*  Pointer to raw data for this insn.  */
91   char                  *address;
92
93   /* Next insn in list.  */
94   struct vliw_insn_list *next;
95 };
96
97 static struct vliw_insn_list single_nop_insn = {
98    VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
99
100 static struct vliw_insn_list double_nop_insn = {
101    VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
102
103 struct vliw_chain
104 {
105   int                   num;
106   int                   insn_count;
107   struct vliw_insn_list *insn_list;
108   struct vliw_chain     *next;
109 };
110
111 static struct vliw_chain        *vliw_chain_top;
112 static struct vliw_chain        *current_vliw_chain;
113 static struct vliw_chain        *previous_vliw_chain;
114 static struct vliw_insn_list    *current_vliw_insn;
115
116 const char comment_chars[]        = ";";
117 const char line_comment_chars[]   = "#";
118 const char line_separator_chars[] = "!"; 
119 const char EXP_CHARS[]            = "eE";
120 const char FLT_CHARS[]            = "dD";
121
122 static FRV_VLIW vliw;
123
124 /* Default machine */
125
126 #ifdef  DEFAULT_CPU_FRV
127 #define DEFAULT_MACHINE bfd_mach_frv
128 #define DEFAULT_FLAGS   EF_FRV_CPU_GENERIC
129
130 #else
131 #ifdef  DEFAULT_CPU_FR300
132 #define DEFAULT_MACHINE bfd_mach_fr300
133 #define DEFAULT_FLAGS   EF_FRV_CPU_FR300
134
135 #else
136 #ifdef  DEFAULT_CPU_SIMPLE
137 #define DEFAULT_MACHINE bfd_mach_frvsimple
138 #define DEFAULT_FLAGS   EF_FRV_CPU_SIMPLE
139
140 #else
141 #ifdef  DEFAULT_CPU_TOMCAT
142 #define DEFAULT_MACHINE bfd_mach_frvtomcat
143 #define DEFAULT_FLAGS   EF_FRV_CPU_TOMCAT
144
145 #else
146 #ifdef  DEFAULT_CPU_FR400
147 #define DEFAULT_MACHINE bfd_mach_fr400
148 #define DEFAULT_FLAGS   EF_FRV_CPU_FR400
149
150 #else
151 #ifdef  DEFAULT_CPU_FR550
152 #define DEFAULT_MACHINE bfd_mach_fr550
153 #define DEFAULT_FLAGS   EF_FRV_CPU_FR550
154
155 #else
156 #define DEFAULT_MACHINE bfd_mach_fr500
157 #define DEFAULT_FLAGS   EF_FRV_CPU_FR500
158 #endif
159 #endif
160 #endif
161 #endif
162 #endif
163 #endif
164
165 static unsigned long frv_mach = bfd_mach_frv;
166 static bfd_boolean fr400_audio;
167
168 /* Flags to set in the elf header */
169 static flagword frv_flags = DEFAULT_FLAGS;
170
171 static int frv_user_set_flags_p = 0;
172 static int frv_pic_p = 0;
173 static const char *frv_pic_flag = (const char *)0;
174
175 /* Print tomcat-specific debugging info.  */
176 static int tomcat_debug = 0;
177
178 /* Tomcat-specific NOP statistics.  */
179 static int tomcat_stats = 0;
180 static int tomcat_doubles = 0;
181 static int tomcat_singles = 0;
182
183 /* Forward reference to static functions */
184 static void frv_set_flags               PARAMS ((int));
185 static void frv_pic_ptr                 PARAMS ((int));
186 static void frv_frob_file_section       PARAMS ((bfd *, asection *, PTR));
187
188 /* The target specific pseudo-ops which we support.  */
189 const pseudo_typeS md_pseudo_table[] =
190 {
191   { "eflags",   frv_set_flags,          0 },
192   { "word",     cons,                   4 },
193   { "picptr",   frv_pic_ptr,            4 },
194   { NULL,       NULL,                   0 }
195 };
196
197 \f
198 #define FRV_SHORTOPTS "G:"
199 const char * md_shortopts = FRV_SHORTOPTS;
200
201 #define OPTION_GPR_32           (OPTION_MD_BASE)
202 #define OPTION_GPR_64           (OPTION_MD_BASE + 1)
203 #define OPTION_FPR_32           (OPTION_MD_BASE + 2)
204 #define OPTION_FPR_64           (OPTION_MD_BASE + 3)
205 #define OPTION_SOFT_FLOAT       (OPTION_MD_BASE + 4)
206 #define OPTION_DWORD_YES        (OPTION_MD_BASE + 5)
207 #define OPTION_DWORD_NO         (OPTION_MD_BASE + 6)
208 #define OPTION_DOUBLE           (OPTION_MD_BASE + 7)
209 #define OPTION_NO_DOUBLE        (OPTION_MD_BASE + 8)
210 #define OPTION_MEDIA            (OPTION_MD_BASE + 9)
211 #define OPTION_NO_MEDIA         (OPTION_MD_BASE + 10)
212 #define OPTION_CPU              (OPTION_MD_BASE + 11)
213 #define OPTION_PIC              (OPTION_MD_BASE + 12)
214 #define OPTION_BIGPIC           (OPTION_MD_BASE + 13)
215 #define OPTION_LIBPIC           (OPTION_MD_BASE + 14)
216 #define OPTION_MULADD           (OPTION_MD_BASE + 15)
217 #define OPTION_NO_MULADD        (OPTION_MD_BASE + 16)
218 #define OPTION_TOMCAT_DEBUG     (OPTION_MD_BASE + 17)
219 #define OPTION_TOMCAT_STATS     (OPTION_MD_BASE + 18)
220 #define OPTION_PACK             (OPTION_MD_BASE + 19)
221 #define OPTION_NO_PACK          (OPTION_MD_BASE + 20)
222 #define OPTION_FDPIC            (OPTION_MD_BASE + 21)
223
224 struct option md_longopts[] =
225 {
226   { "mgpr-32",          no_argument,            NULL, OPTION_GPR_32        },
227   { "mgpr-64",          no_argument,            NULL, OPTION_GPR_64        },
228   { "mfpr-32",          no_argument,            NULL, OPTION_FPR_32        },
229   { "mfpr-64",          no_argument,            NULL, OPTION_FPR_64        },
230   { "mhard-float",      no_argument,            NULL, OPTION_FPR_64        },
231   { "msoft-float",      no_argument,            NULL, OPTION_SOFT_FLOAT    },
232   { "mdword",           no_argument,            NULL, OPTION_DWORD_YES     },
233   { "mno-dword",        no_argument,            NULL, OPTION_DWORD_NO      },
234   { "mdouble",          no_argument,            NULL, OPTION_DOUBLE        },
235   { "mno-double",       no_argument,            NULL, OPTION_NO_DOUBLE     },
236   { "mmedia",           no_argument,            NULL, OPTION_MEDIA         },
237   { "mno-media",        no_argument,            NULL, OPTION_NO_MEDIA      },
238   { "mcpu",             required_argument,      NULL, OPTION_CPU           },
239   { "mpic",             no_argument,            NULL, OPTION_PIC           },
240   { "mPIC",             no_argument,            NULL, OPTION_BIGPIC        },
241   { "mlibrary-pic",     no_argument,            NULL, OPTION_LIBPIC        },
242   { "mmuladd",          no_argument,            NULL, OPTION_MULADD        },
243   { "mno-muladd",       no_argument,            NULL, OPTION_NO_MULADD     },
244   { "mtomcat-debug",    no_argument,            NULL, OPTION_TOMCAT_DEBUG  },
245   { "mtomcat-stats",    no_argument,            NULL, OPTION_TOMCAT_STATS  },
246   { "mpack",            no_argument,            NULL, OPTION_PACK          },
247   { "mno-pack",         no_argument,            NULL, OPTION_NO_PACK       },
248   { "mfdpic",           no_argument,            NULL, OPTION_FDPIC         },
249   { NULL,               no_argument,            NULL, 0                 },
250 };
251
252 size_t md_longopts_size = sizeof (md_longopts);
253
254 /* What value to give to bfd_set_gp_size.  */
255 static int g_switch_value = 8;
256
257 int
258 md_parse_option (c, arg)
259      int    c;
260      char * arg;
261 {
262   switch (c)
263     {
264     default:
265       return 0;
266
267     case 'G':
268       g_switch_value = atoi (arg);
269       if (! g_switch_value)
270         frv_flags |= EF_FRV_G0;
271       break;
272
273     case OPTION_GPR_32:
274       frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
275       break;
276
277     case OPTION_GPR_64:
278       frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
279       break;
280
281     case OPTION_FPR_32:
282       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
283       break;
284
285     case OPTION_FPR_64:
286       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
287       break;
288
289     case OPTION_SOFT_FLOAT:
290       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
291       break;
292
293     case OPTION_DWORD_YES:
294       frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
295       break;
296
297     case OPTION_DWORD_NO:
298       frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
299       break;
300
301     case OPTION_DOUBLE:
302       frv_flags |= EF_FRV_DOUBLE;
303       break;
304
305     case OPTION_NO_DOUBLE:
306       frv_flags &= ~EF_FRV_DOUBLE;
307       break;
308
309     case OPTION_MEDIA:
310       frv_flags |= EF_FRV_MEDIA;
311       break;
312
313     case OPTION_NO_MEDIA:
314       frv_flags &= ~EF_FRV_MEDIA;
315       break;
316
317     case OPTION_MULADD:
318       frv_flags |= EF_FRV_MULADD;
319       break;
320
321     case OPTION_NO_MULADD:
322       frv_flags &= ~EF_FRV_MULADD;
323       break;
324
325     case OPTION_PACK:
326       frv_flags &= ~EF_FRV_NOPACK;
327       break;
328
329     case OPTION_NO_PACK:
330       frv_flags |= EF_FRV_NOPACK;
331       break;
332
333     case OPTION_CPU:
334       {
335         char *p;
336         int cpu_flags = EF_FRV_CPU_GENERIC;
337
338         /* Identify the processor type */
339         p = arg;
340         if (strcmp (p, "frv") == 0)
341           {
342             cpu_flags = EF_FRV_CPU_GENERIC;
343             frv_mach = bfd_mach_frv;
344           }
345
346         else if (strcmp (p, "fr500") == 0)
347           {
348             cpu_flags = EF_FRV_CPU_FR500;
349             frv_mach = bfd_mach_fr500;
350           }
351
352         else if (strcmp (p, "fr550") == 0)
353           {
354             cpu_flags = EF_FRV_CPU_FR550;
355             frv_mach = bfd_mach_fr550;
356           }
357
358         else if (strcmp (p, "fr450") == 0)
359           {
360             cpu_flags = EF_FRV_CPU_FR450;
361             frv_mach = bfd_mach_fr450;
362           }
363
364         else if (strcmp (p, "fr405") == 0)
365           {
366             cpu_flags = EF_FRV_CPU_FR405;
367             frv_mach = bfd_mach_fr400;
368             fr400_audio = TRUE;
369           }
370
371         else if (strcmp (p, "fr400") == 0)
372           {
373             cpu_flags = EF_FRV_CPU_FR400;
374             frv_mach = bfd_mach_fr400;
375             fr400_audio = FALSE;
376           }
377
378         else if (strcmp (p, "fr300") == 0)
379           {
380             cpu_flags = EF_FRV_CPU_FR300;
381             frv_mach = bfd_mach_fr300;
382           }
383
384         else if (strcmp (p, "simple") == 0)
385           {
386             cpu_flags = EF_FRV_CPU_SIMPLE;
387             frv_mach = bfd_mach_frvsimple;
388             frv_flags |= EF_FRV_NOPACK;
389           }
390
391         else if (strcmp (p, "tomcat") == 0)
392           {
393             cpu_flags = EF_FRV_CPU_TOMCAT;
394             frv_mach = bfd_mach_frvtomcat;
395           }
396
397         else
398           {
399             as_fatal ("Unknown cpu -mcpu=%s", arg);
400             return 0;
401           }
402
403         frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
404       }
405       break;
406
407     case OPTION_PIC:
408       frv_flags |= EF_FRV_PIC;
409       frv_pic_p = 1;
410       frv_pic_flag = "-fpic";
411       break;
412
413     case OPTION_BIGPIC:
414       frv_flags |= EF_FRV_BIGPIC;
415       frv_pic_p = 1;
416       frv_pic_flag = "-fPIC";
417       break;
418
419     case OPTION_LIBPIC:
420       frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
421       frv_pic_p = 1;
422       frv_pic_flag = "-mlibrary-pic";
423       g_switch_value = 0;
424       break;
425
426     case OPTION_FDPIC:
427       frv_flags |= EF_FRV_FDPIC;
428       frv_pic_flag = "-mfdpic";
429       break;
430
431     case OPTION_TOMCAT_DEBUG:
432       tomcat_debug = 1;
433       break;
434
435     case OPTION_TOMCAT_STATS:
436       tomcat_stats = 1;
437       break;
438     }
439
440   return 1;
441 }
442
443 void
444 md_show_usage (stream)
445   FILE * stream;
446 {
447   fprintf (stream, _("FRV specific command line options:\n"));
448   fprintf (stream, _("-G n         Data >= n bytes is in small data area\n"));
449   fprintf (stream, _("-mgpr-32     Note 32 gprs are used\n"));
450   fprintf (stream, _("-mgpr-64     Note 64 gprs are used\n"));
451   fprintf (stream, _("-mfpr-32     Note 32 fprs are used\n"));
452   fprintf (stream, _("-mfpr-64     Note 64 fprs are used\n"));
453   fprintf (stream, _("-msoft-float Note software fp is used\n"));
454   fprintf (stream, _("-mdword      Note stack is aligned to a 8 byte boundary\n"));
455   fprintf (stream, _("-mno-dword   Note stack is aligned to a 4 byte boundary\n"));
456   fprintf (stream, _("-mdouble     Note fp double insns are used\n"));
457   fprintf (stream, _("-mmedia      Note media insns are used\n"));
458   fprintf (stream, _("-mmuladd     Note multiply add/subtract insns are used\n"));
459   fprintf (stream, _("-mpack       Note instructions are packed\n"));
460   fprintf (stream, _("-mno-pack    Do not allow instructions to be packed\n"));
461   fprintf (stream, _("-mpic        Note small position independent code\n"));
462   fprintf (stream, _("-mPIC        Note large position independent code\n"));
463   fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
464   fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr405|fr450|fr300|frv|simple|tomcat}\n"));
465   fprintf (stream, _("             Record the cpu type\n"));
466   fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
467   fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
468
469
470 \f
471 void
472 md_begin ()
473 {
474   /* Initialize the `cgen' interface.  */
475   
476   /* Set the machine number and endian.  */
477   gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
478                                          CGEN_CPU_OPEN_ENDIAN,
479                                          CGEN_ENDIAN_BIG,
480                                          CGEN_CPU_OPEN_END);
481   frv_cgen_init_asm (gas_cgen_cpu_desc);
482
483   /* This is a callback from cgen to gas to parse operands.  */
484   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
485
486   /* Set the ELF flags if desired. */
487   if (frv_flags)
488     bfd_set_private_flags (stdoutput, frv_flags);
489
490   /* Set the machine type */
491   bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
492
493   /* Set up gp size so we can put local common items in .sbss */
494   bfd_set_gp_size (stdoutput, g_switch_value);
495
496   frv_vliw_reset (& vliw, frv_mach, frv_flags);
497 }
498
499 int chain_num = 0;
500
501 struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
502
503 struct vliw_insn_list *
504 frv_insert_vliw_insn (count)
505       bfd_boolean count;
506 {
507   struct vliw_insn_list *vliw_insn_list_entry;
508   struct vliw_chain     *vliw_chain_entry;
509
510   if (current_vliw_chain == NULL)
511     {
512       vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
513       vliw_chain_entry->insn_count = 0;
514       vliw_chain_entry->insn_list  = NULL;
515       vliw_chain_entry->next       = NULL;
516       vliw_chain_entry->num        = chain_num++;
517
518       if (!vliw_chain_top)
519         vliw_chain_top = vliw_chain_entry;
520       current_vliw_chain = vliw_chain_entry;
521       if (previous_vliw_chain)
522         previous_vliw_chain->next = vliw_chain_entry;
523     }
524
525   vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
526   vliw_insn_list_entry->type      = VLIW_GENERIC_TYPE;
527   vliw_insn_list_entry->insn      = NULL;
528   vliw_insn_list_entry->sym       = NULL;
529   vliw_insn_list_entry->snop_frag = NULL;
530   vliw_insn_list_entry->dnop_frag = NULL;
531   vliw_insn_list_entry->next      = NULL;
532
533   if (count)
534     current_vliw_chain->insn_count++;
535
536   if (current_vliw_insn)
537     current_vliw_insn->next = vliw_insn_list_entry;
538   current_vliw_insn = vliw_insn_list_entry;
539
540   if (!current_vliw_chain->insn_list)
541     current_vliw_chain->insn_list = current_vliw_insn;
542
543   return vliw_insn_list_entry;
544 }
545
546   /* Identify the following cases:
547  
548      1) A VLIW insn that contains both a branch and the branch destination.
549         This requires the insertion of two vliw instructions before the
550         branch.  The first consists of two nops.  The second consists of
551         a single nop.
552  
553      2) A single instruction VLIW insn which is the destination of a branch
554         that is in the next VLIW insn.  This requires the insertion of a vliw
555         insn containing two nops before the branch.
556  
557      3) A double instruction VLIW insn which contains the destination of a
558         branch that is in the next VLIW insn.  This requires the insertion of
559         a VLIW insn containing a single nop before the branch.
560  
561      4) A single instruction VLIW insn which contains branch destination (x),
562         followed by a single instruction VLIW insn which does not contain
563         the branch to (x), followed by a VLIW insn which does contain the branch
564         to (x).  This requires the insertion of a VLIW insn containing a single
565         nop before the VLIW instruction containing the branch.
566  
567   */
568 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
569 #define FRV_NOP_PACK   0x00880000  /* ori.p  gr0,0,gr0 */
570 #define FRV_NOP_NOPACK 0x80880000  /* ori    gr0,0,gr0 */
571
572 /* Check a vliw insn for an insn of type containing the sym passed in label_sym.  */
573
574 static struct vliw_insn_list *frv_find_in_vliw
575   PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
576
577 static struct vliw_insn_list *
578 frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
579     enum vliw_insn_type vliw_insn_type;
580     struct vliw_chain *this_chain;
581     symbolS *label_sym;
582 {
583
584   struct vliw_insn_list *the_insn;
585
586   if (!this_chain)
587     return NULL;
588
589   for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
590     {
591       if (the_insn->type == vliw_insn_type
592           && the_insn->sym == label_sym)
593         return the_insn;
594     }
595
596   return NULL;
597 }
598
599 enum vliw_nop_type
600 {
601   /* A Vliw insn containing a single nop insn.  */
602   VLIW_SINGLE_NOP,
603   
604   /* A Vliw insn containing two nop insns.  */
605   VLIW_DOUBLE_NOP,
606
607   /* Two vliw insns.  The first containing two nop insns.  
608      The second contain a single nop insn.  */
609   VLIW_DOUBLE_THEN_SINGLE_NOP
610 };
611
612 static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
613
614 static void
615 frv_debug_tomcat (start_chain)
616    struct vliw_chain *start_chain;
617 {
618    struct vliw_chain *this_chain;
619    struct vliw_insn_list *this_insn;
620    int i = 1;
621
622   for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
623     {
624       fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
625
626       for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
627         {
628           if (this_insn->type == VLIW_LABEL_TYPE)
629             fprintf (stderr, "Label Value: %d\n", (int) this_insn->sym);
630           else if (this_insn->type == VLIW_BRANCH_TYPE)
631             fprintf (stderr, "%s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
632           else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
633             fprintf (stderr, "nop'd %s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
634           else if (this_insn->type == VLIW_NOP_TYPE)
635             fprintf (stderr, "Nop\n");
636           else
637             fprintf (stderr, "  %s\n", this_insn->insn->base->name);
638         }
639    }
640 }
641
642 static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
643
644 static void
645 frv_adjust_vliw_count (this_chain)
646     struct vliw_chain *this_chain;
647 {
648   struct vliw_insn_list *this_insn;
649
650   this_chain->insn_count = 0;
651
652   for (this_insn = this_chain->insn_list;
653        this_insn;
654        this_insn = this_insn->next)
655     {
656       if (this_insn->type != VLIW_LABEL_TYPE)
657         this_chain->insn_count++;
658     }
659
660 }
661
662 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
663    Rechain the vliw insn.  */
664
665 static struct vliw_chain *frv_tomcat_shuffle
666   PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
667
668 static struct vliw_chain *
669 frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
670    enum vliw_nop_type    this_nop_type;
671    struct vliw_chain     *vliw_to_split;
672    struct vliw_insn_list *insert_before_insn;
673 {
674
675   bfd_boolean pack_prev = FALSE;
676   struct vliw_chain *return_me = NULL;
677   struct vliw_insn_list *prev_insn = NULL;
678   struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
679
680   struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
681   struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
682   struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
683   struct vliw_chain *curr_vliw = vliw_chain_top;
684   struct vliw_chain *prev_vliw = NULL;
685
686   while (curr_insn && curr_insn != insert_before_insn)
687     {
688       /* We can't set the packing bit on a label.  If we have the case
689          label 1:
690          label 2:
691          label 3:
692            branch that needs nops
693         Then don't set pack bit later.  */
694
695       if (curr_insn->type != VLIW_LABEL_TYPE)
696         pack_prev = TRUE;
697       prev_insn = curr_insn;
698       curr_insn = curr_insn->next;
699     } 
700
701   while (curr_vliw && curr_vliw != vliw_to_split)
702     {
703       prev_vliw = curr_vliw;
704       curr_vliw = curr_vliw->next;
705     }
706
707   switch (this_nop_type)
708     {
709     case VLIW_SINGLE_NOP:
710       if (!prev_insn)
711         {
712         /* Branch is first,  Insert the NOP prior to this vliw insn.  */
713         if (prev_vliw)
714           prev_vliw->next = single_nop;
715         else
716           vliw_chain_top = single_nop;
717         single_nop->next = vliw_to_split;
718         vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
719         return_me = vliw_to_split;
720         }
721       else
722         {
723           /* Set the packing bit on the previous insn.  */
724           if (pack_prev)
725             {
726               unsigned char *buffer = prev_insn->address;
727               buffer[0] |= 0x80;
728             }
729           /* The branch is in the middle.  Split this vliw insn into first
730              and second parts.  Insert the NOP inbetween.  */
731
732           second_part->insn_list = insert_before_insn;
733           second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
734           second_part->next      = vliw_to_split->next;
735           frv_adjust_vliw_count (second_part);
736
737           single_nop->next       = second_part;
738  
739           vliw_to_split->next    = single_nop;
740           prev_insn->next        = NULL;
741  
742           return_me = second_part;
743           frv_adjust_vliw_count (vliw_to_split);
744         }
745       break;
746
747     case VLIW_DOUBLE_NOP:
748       if (!prev_insn)
749         {
750         /* Branch is first,  Insert the NOP prior to this vliw insn.  */
751         if (prev_vliw)
752           prev_vliw->next = double_nop;
753         else
754           vliw_chain_top = double_nop;
755
756         double_nop->next = vliw_to_split;
757         return_me = vliw_to_split;
758         vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
759         }
760       else
761         {
762           /* Set the packing bit on the previous insn.  */
763           if (pack_prev)
764             {
765               unsigned char *buffer = prev_insn->address;
766               buffer[0] |= 0x80;
767             }
768
769         /* The branch is in the middle.  Split this vliw insn into first
770            and second parts.  Insert the NOP inbetween.  */
771           second_part->insn_list = insert_before_insn;
772           second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
773           second_part->next      = vliw_to_split->next;
774           frv_adjust_vliw_count (second_part);
775  
776           double_nop->next       = second_part;
777  
778           vliw_to_split->next    = single_nop;
779           prev_insn->next        = NULL;
780           frv_adjust_vliw_count (vliw_to_split);
781  
782           return_me = second_part;
783         }
784       break;
785
786     case VLIW_DOUBLE_THEN_SINGLE_NOP:
787       double_nop->next = single_nop;
788       double_nop->insn_count = 2;
789       double_nop->insn_list = &double_nop_insn;
790       single_nop->insn_count = 1;
791       single_nop->insn_list = &single_nop_insn;
792
793       if (!prev_insn)
794         {
795           /* The branch is the first insn in this vliw.  Don't split the vliw.  Insert
796              the nops prior to this vliw.  */
797           if (prev_vliw)
798             prev_vliw->next = double_nop;
799           else
800             vliw_chain_top = double_nop;
801  
802           single_nop->next = vliw_to_split;
803           return_me = vliw_to_split;
804           vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
805         }
806       else
807         {
808           /* Set the packing bit on the previous insn.  */
809           if (pack_prev)
810             {
811               unsigned char *buffer = prev_insn->address;
812               buffer[0] |= 0x80;
813             }
814
815           /* The branch is in the middle of this vliw insn.  Split into first and
816              second parts.  Insert the nop vliws in between.  */  
817           second_part->insn_list = insert_before_insn;
818           second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
819           second_part->next      = vliw_to_split->next;
820           frv_adjust_vliw_count (second_part);
821
822           single_nop->next       = second_part;
823
824           vliw_to_split->next    = double_nop;
825           prev_insn->next        = NULL;
826           frv_adjust_vliw_count (vliw_to_split);
827
828           return_me = second_part;
829         }
830       break;
831     }
832
833   return return_me;
834 }
835
836 static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
837
838 static void
839 frv_tomcat_analyze_vliw_chains ()
840 {
841   struct vliw_chain *vliw1 = NULL;
842   struct vliw_chain *vliw2 = NULL;
843   struct vliw_chain *vliw3 = NULL;
844
845   struct vliw_insn_list *this_insn = NULL;
846   struct vliw_insn_list *temp_insn = NULL;
847
848   /* We potentially need to look at three VLIW insns to determine if the
849      workaround is required.  Set them up.  Ignore existing nops during analysis. */
850
851 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
852   if (VLIW1 && VLIW1->next)                      \
853     VLIW2 = VLIW1->next;                         \
854   else                                           \
855     VLIW2 = NULL;                                \
856   if (VLIW2 && VLIW2->next)                      \
857     VLIW3 = VLIW2->next;                         \
858   else                                           \
859     VLIW3 = NULL
860
861   vliw1 = vliw_chain_top;
862
863 workaround_top:
864
865   FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
866
867   if (!vliw1)
868     return;
869
870   if (vliw1->insn_count == 1)
871     {
872       /* check vliw1 for a label. */
873       if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
874         {
875           temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
876           if (temp_insn)
877             {
878               vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
879               temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
880               vliw1 = vliw1->next;
881               if (tomcat_stats)
882                 tomcat_doubles++;
883               goto workaround_top;
884             }
885           else if (vliw2 
886                    && vliw2->insn_count == 1
887                    && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
888             {
889               temp_insn->snop_frag->fr_subtype = NOP_KEEP;
890               vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
891               if (tomcat_stats)
892                 tomcat_singles++;
893               goto workaround_top;
894             }
895         }
896     }
897
898   if (vliw1->insn_count == 2)
899     {
900       struct vliw_insn_list *this_insn;
901  
902       /* check vliw1 for a label. */
903       for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
904         {
905           if (this_insn->type == VLIW_LABEL_TYPE)
906             {
907               if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
908                 {
909                   temp_insn->snop_frag->fr_subtype = NOP_KEEP;
910                   vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
911                   if (tomcat_stats)
912                     tomcat_singles++;
913                 }
914               else
915                 vliw1 = vliw1->next;
916               goto workaround_top;
917             }
918         }
919     }
920   /* Examine each insn in this VLIW.  Look for the workaround criteria.  */
921   for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
922     {
923       /* Don't look at labels or nops.  */
924       while (this_insn
925              && (this_insn->type == VLIW_LABEL_TYPE
926                  || this_insn->type == VLIW_NOP_TYPE
927                  || this_insn->type == VLIW_BRANCH_HAS_NOPS))
928         this_insn = this_insn->next;
929
930       if (!this_insn)
931         {
932           vliw1 = vliw2;
933           goto workaround_top;
934         }
935
936       if (frv_is_branch_insn (this_insn->insn))
937         {
938           if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
939             {
940               /* Insert [nop/nop] [nop] before branch.  */
941               this_insn->snop_frag->fr_subtype = NOP_KEEP;
942               this_insn->dnop_frag->fr_subtype = NOP_KEEP;
943               vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
944               goto workaround_top;
945             }
946         }
947
948
949     }
950   /* This vliw insn checks out okay.  Take a look at the next one.  */
951   vliw1 = vliw1->next;
952   goto workaround_top;
953 }
954
955 void
956 frv_tomcat_workaround ()
957 {
958   if (frv_mach != bfd_mach_frvtomcat)
959     return;
960
961   if (tomcat_debug)
962     frv_debug_tomcat (vliw_chain_top);
963
964   frv_tomcat_analyze_vliw_chains ();
965
966   if (tomcat_stats)
967     {
968       fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
969       fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
970     }
971 }
972
973 static int
974 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
975 {
976   int acc;
977   switch (CGEN_INSN_NUM (insn->insn))
978     {
979     case FRV_INSN_MADDACCS:
980     case FRV_INSN_MSUBACCS:
981     case FRV_INSN_MDADDACCS:
982     case FRV_INSN_MDSUBACCS:
983     case FRV_INSN_MASACCS:
984     case FRV_INSN_MDASACCS:
985       acc = insn->fields.f_ACC40Si;
986       if (acc < low || acc > hi)
987         return 1; /* out of range */
988       acc = insn->fields.f_ACC40Sk;
989       if (acc < low || acc > hi)
990         return 1; /* out of range */
991       break;
992     case FRV_INSN_MMULHS:
993     case FRV_INSN_MMULHU:
994     case FRV_INSN_MMULXHS:
995     case FRV_INSN_MMULXHU:
996     case FRV_INSN_CMMULHS:
997     case FRV_INSN_CMMULHU:
998     case FRV_INSN_MQMULHS:
999     case FRV_INSN_MQMULHU:
1000     case FRV_INSN_MQMULXHS:
1001     case FRV_INSN_MQMULXHU:
1002     case FRV_INSN_CMQMULHS:
1003     case FRV_INSN_CMQMULHU:
1004     case FRV_INSN_MMACHS:
1005     case FRV_INSN_MMRDHS:
1006     case FRV_INSN_CMMACHS: 
1007     case FRV_INSN_MQMACHS:
1008     case FRV_INSN_CMQMACHS:
1009     case FRV_INSN_MQXMACHS:
1010     case FRV_INSN_MQXMACXHS:
1011     case FRV_INSN_MQMACXHS:
1012     case FRV_INSN_MCPXRS:
1013     case FRV_INSN_MCPXIS:
1014     case FRV_INSN_CMCPXRS:
1015     case FRV_INSN_CMCPXIS:
1016     case FRV_INSN_MQCPXRS:
1017     case FRV_INSN_MQCPXIS:
1018      acc = insn->fields.f_ACC40Sk;
1019       if (acc < low || acc > hi)
1020         return 1; /* out of range */
1021       break;
1022     case FRV_INSN_MMACHU:
1023     case FRV_INSN_MMRDHU:
1024     case FRV_INSN_CMMACHU:
1025     case FRV_INSN_MQMACHU:
1026     case FRV_INSN_CMQMACHU:
1027     case FRV_INSN_MCPXRU:
1028     case FRV_INSN_MCPXIU:
1029     case FRV_INSN_CMCPXRU:
1030     case FRV_INSN_CMCPXIU:
1031     case FRV_INSN_MQCPXRU:
1032     case FRV_INSN_MQCPXIU:
1033       acc = insn->fields.f_ACC40Uk;
1034       if (acc < low || acc > hi)
1035         return 1; /* out of range */
1036       break;
1037     default:
1038       break;
1039     }
1040   return 0; /* all is ok */
1041 }
1042
1043 static int
1044 fr550_check_acc_range (FRV_VLIW *vliw, frv_insn *insn)
1045 {
1046   switch ((*vliw->current_vliw)[vliw->next_slot - 1])
1047     {
1048     case UNIT_FM0:
1049     case UNIT_FM2:
1050       return fr550_check_insn_acc_range (insn, 0, 3);
1051     case UNIT_FM1:
1052     case UNIT_FM3:
1053       return fr550_check_insn_acc_range (insn, 4, 7);
1054     default:
1055       break;
1056     }
1057   return 0; /* all is ok */
1058 }
1059
1060 /* Return true if the target implements instruction INSN.  */
1061
1062 static bfd_boolean
1063 target_implements_insn_p (const CGEN_INSN *insn)
1064 {
1065   switch (frv_mach)
1066     {
1067     default:
1068       /* bfd_mach_frv or generic.  */
1069       return TRUE;
1070
1071     case bfd_mach_fr300:
1072     case bfd_mach_frvsimple:
1073       return CGEN_INSN_MACH_HAS_P (insn, MACH_SIMPLE);
1074
1075     case bfd_mach_fr400:
1076       return ((fr400_audio || !CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_AUDIO))
1077               && CGEN_INSN_MACH_HAS_P (insn, MACH_FR400));
1078
1079     case bfd_mach_fr450:
1080       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR450);
1081
1082     case bfd_mach_fr500:
1083       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR500);
1084
1085     case bfd_mach_fr550:
1086       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR550);
1087     }
1088 }
1089
1090 void
1091 md_assemble (str)
1092      char * str;
1093 {
1094   frv_insn insn;
1095   char *errmsg;
1096   int packing_constraint;
1097   finished_insnS  finished_insn;
1098   fragS *double_nop_frag = NULL;
1099   fragS *single_nop_frag = NULL;
1100   struct vliw_insn_list *vliw_insn_list_entry = NULL;
1101
1102   /* Initialize GAS's cgen interface for a new instruction.  */
1103   gas_cgen_init_parse ();
1104
1105   memset (&insn, 0, sizeof (insn));
1106
1107   insn.insn = frv_cgen_assemble_insn
1108     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
1109   
1110   if (!insn.insn)
1111     {
1112       as_bad (errmsg);
1113       return;
1114     }
1115   
1116   /* If the cpu is tomcat, then we need to insert nops to workaround
1117      hardware limitations.  We need to keep track of each vliw unit
1118      and examine the length of the unit and the individual insns
1119      within the unit to determine the number and location of the
1120      required nops.  */
1121   if (frv_mach == bfd_mach_frvtomcat)
1122     {
1123       /* If we've just finished a VLIW insn OR this is a branch,
1124          then start up a new frag.  Fill it with nops.  We will get rid
1125          of those that are not required after we've seen all of the 
1126          instructions but before we start resolving fixups.  */
1127       if ( !FRV_IS_NOP (insn)
1128           && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1129         {
1130           char *buffer;
1131
1132           frag_wane (frag_now);
1133           frag_new (0);
1134           double_nop_frag = frag_now;
1135           buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
1136           md_number_to_chars (buffer, FRV_NOP_PACK, 4);
1137           md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
1138
1139           frag_wane (frag_now);
1140           frag_new (0);
1141           single_nop_frag = frag_now;
1142           buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
1143           md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
1144         }
1145
1146       vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
1147       vliw_insn_list_entry->insn   = insn.insn;
1148       if (frv_is_branch_insn (insn.insn))
1149         vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
1150
1151       if ( !FRV_IS_NOP (insn)
1152           && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1153         {
1154           vliw_insn_list_entry->snop_frag = single_nop_frag;
1155           vliw_insn_list_entry->dnop_frag = double_nop_frag;
1156         }
1157     }
1158
1159   /* Make sure that this insn does not violate the VLIW packing constraints.  */
1160   /* -mno-pack disallows any packing whatsoever.  */
1161   if (frv_flags & EF_FRV_NOPACK)
1162     {
1163       if (! insn.fields.f_pack)
1164         {
1165           as_bad (_("VLIW packing used for -mno-pack"));
1166           return;
1167         }
1168     }
1169   /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1170      instructions, don't do vliw checking.  */
1171   else if (frv_mach != bfd_mach_frv)
1172     {
1173       if (!target_implements_insn_p (insn.insn))
1174         {
1175           as_bad (_("Instruction not supported by this architecture"));
1176           return;
1177         }
1178       packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1179       if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1180         packing_constraint = fr550_check_acc_range (& vliw, & insn);
1181       if (insn.fields.f_pack)
1182         frv_vliw_reset (& vliw, frv_mach, frv_flags);
1183       if (packing_constraint)
1184         {
1185           as_bad (_("VLIW packing constraint violation"));
1186           return;
1187         }
1188     }
1189
1190   /* Doesn't really matter what we pass for RELAX_P here.  */
1191   gas_cgen_finish_insn (insn.insn, insn.buffer,
1192                         CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1193
1194
1195   /* If the cpu is tomcat, then we need to insert nops to workaround
1196      hardware limitations.  We need to keep track of each vliw unit
1197      and examine the length of the unit and the individual insns
1198      within the unit to determine the number and location of the
1199      required nops.  */
1200   if (frv_mach == bfd_mach_frvtomcat)
1201     {
1202       if (vliw_insn_list_entry)
1203         vliw_insn_list_entry->address = finished_insn.addr;
1204       else
1205         abort();
1206
1207       if (insn.fields.f_pack)
1208         {
1209           /* We've completed a VLIW insn.  */
1210           previous_vliw_chain = current_vliw_chain;
1211           current_vliw_chain = NULL;
1212           current_vliw_insn  = NULL;
1213         } 
1214     }
1215 }
1216
1217 /* The syntax in the manual says constants begin with '#'.
1218    We just ignore it.  */
1219
1220 void 
1221 md_operand (expressionP)
1222      expressionS * expressionP;
1223 {
1224   if (* input_line_pointer == '#')
1225     {
1226       input_line_pointer ++;
1227       expression (expressionP);
1228     }
1229 }
1230
1231 valueT
1232 md_section_align (segment, size)
1233      segT   segment;
1234      valueT size;
1235 {
1236   int align = bfd_get_section_alignment (stdoutput, segment);
1237   return ((size + (1 << align) - 1) & (-1 << align));
1238 }
1239
1240 symbolS *
1241 md_undefined_symbol (name)
1242   char * name ATTRIBUTE_UNUSED;
1243 {
1244   return 0;
1245 }
1246 \f
1247 /* Interface to relax_segment.  */
1248
1249 /* FIXME: Build table by hand, get it working, then machine generate.  */
1250 const relax_typeS md_relax_table[] =
1251 {
1252   {1, 1, 0, 0},
1253   {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1254   {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1255   {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1256 };
1257
1258 long
1259 frv_relax_frag (fragP, stretch)
1260      fragS   *fragP ATTRIBUTE_UNUSED;
1261      long    stretch ATTRIBUTE_UNUSED;
1262 {
1263   return 0;
1264 }
1265
1266 /* Return an initial guess of the length by which a fragment must grow to
1267    hold a branch to reach its destination.
1268    Also updates fr_type/fr_subtype as necessary.
1269
1270    Called just before doing relaxation.
1271    Any symbol that is now undefined will not become defined.
1272    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1273    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1274    Although it may not be explicit in the frag, pretend fr_var starts with a
1275    0 value.  */
1276
1277 int
1278 md_estimate_size_before_relax (fragP, segment)
1279      fragS * fragP;
1280      segT    segment ATTRIBUTE_UNUSED;
1281 {
1282   switch (fragP->fr_subtype)
1283     {
1284     case NOP_KEEP:
1285       return fragP->fr_var;
1286
1287     default:
1288     case NOP_DELETE:
1289       return 0;
1290     }     
1291
1292
1293 /* *fragP has been relaxed to its final size, and now needs to have
1294    the bytes inside it modified to conform to the new size.
1295
1296    Called after relaxation is finished.
1297    fragP->fr_type == rs_machine_dependent.
1298    fragP->fr_subtype is the subtype of what the address relaxed to.  */
1299
1300 void
1301 md_convert_frag (abfd, sec, fragP)
1302   bfd *   abfd ATTRIBUTE_UNUSED;
1303   segT    sec ATTRIBUTE_UNUSED;
1304   fragS * fragP;
1305 {
1306   switch (fragP->fr_subtype)
1307     {
1308     default:
1309     case NOP_DELETE:
1310       return;
1311
1312     case NOP_KEEP:
1313       fragP->fr_fix = fragP->fr_var;
1314       fragP->fr_var = 0;
1315       return;   
1316     }
1317 }
1318 \f
1319 /* Functions concerning relocs.  */
1320
1321 /* The location from which a PC relative jump should be calculated,
1322    given a PC relative reloc.  */
1323
1324 long
1325 md_pcrel_from_section (fixP, sec)
1326      fixS * fixP;
1327      segT   sec;
1328 {
1329   if (TC_FORCE_RELOCATION (fixP)
1330       || (fixP->fx_addsy != (symbolS *) NULL
1331           && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1332     {
1333       /* If we can't adjust this relocation, or if it references a
1334          local symbol in a different section (which
1335          TC_FORCE_RELOCATION can't check), let the linker figure it
1336          out.  */
1337       return 0;
1338     }
1339
1340   return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1341 }
1342
1343 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1344    Returns BFD_RELOC_NONE if no reloc type can be found.
1345    *FIXP may be modified if desired.  */
1346
1347 bfd_reloc_code_real_type
1348 md_cgen_lookup_reloc (insn, operand, fixP)
1349      const CGEN_INSN *    insn ATTRIBUTE_UNUSED;
1350      const CGEN_OPERAND * operand;
1351      fixS *               fixP;
1352 {
1353   switch (operand->type)
1354     {
1355     case FRV_OPERAND_LABEL16:
1356       fixP->fx_pcrel = TRUE;
1357       return BFD_RELOC_FRV_LABEL16;
1358
1359     case FRV_OPERAND_LABEL24:
1360       fixP->fx_pcrel = TRUE;
1361       return BFD_RELOC_FRV_LABEL24;
1362
1363     case FRV_OPERAND_UHI16:
1364     case FRV_OPERAND_ULO16:
1365     case FRV_OPERAND_SLO16:
1366
1367       /* The relocation type should be recorded in opinfo */
1368       if (fixP->fx_cgen.opinfo != 0)
1369         return fixP->fx_cgen.opinfo;
1370       break;
1371
1372     case FRV_OPERAND_D12:
1373     case FRV_OPERAND_S12:
1374       if (fixP->fx_cgen.opinfo != 0)
1375         return fixP->fx_cgen.opinfo;
1376
1377       return BFD_RELOC_FRV_GPREL12;
1378
1379     case FRV_OPERAND_U12:
1380       return BFD_RELOC_FRV_GPRELU12;
1381
1382     default: 
1383       break;
1384     }
1385   return BFD_RELOC_NONE;
1386 }
1387
1388
1389 /* See whether we need to force a relocation into the output file.
1390    This is used to force out switch and PC relative relocations when
1391    relaxing.  */
1392
1393 int
1394 frv_force_relocation (fix)
1395      fixS * fix;
1396 {
1397   if (fix->fx_r_type == BFD_RELOC_FRV_GPREL12
1398       || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
1399     return 1;
1400
1401   return generic_force_reloc (fix);
1402 }
1403
1404 /* Apply a fixup that could be resolved within the assembler.  */
1405
1406 void
1407 md_apply_fix3 (fixP, valP, seg)
1408      fixS *   fixP;
1409      valueT * valP;
1410      segT     seg;
1411 {
1412   if (fixP->fx_addsy == 0)
1413     switch (fixP->fx_cgen.opinfo)
1414       {
1415       case BFD_RELOC_FRV_HI16:
1416         *valP >>= 16;
1417         /* Fall through.  */
1418       case BFD_RELOC_FRV_LO16:
1419         *valP &= 0xffff;
1420         break;
1421       }
1422
1423   gas_cgen_md_apply_fix3 (fixP, valP, seg);
1424   return;
1425 }
1426
1427 \f
1428 /* Write a value out to the object file, using the appropriate endianness.  */
1429
1430 void
1431 frv_md_number_to_chars (buf, val, n)
1432      char * buf;
1433      valueT val;
1434      int    n;
1435 {
1436   number_to_chars_bigendian (buf, val, n);
1437 }
1438
1439 /* Turn a string in input_line_pointer into a floating point constant of type
1440    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
1441    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
1442 */
1443
1444 /* Equal to MAX_PRECISION in atof-ieee.c */
1445 #define MAX_LITTLENUMS 6
1446
1447 char *
1448 md_atof (type, litP, sizeP)
1449      char   type;
1450      char * litP;
1451      int *  sizeP;
1452 {
1453   int              i;
1454   int              prec;
1455   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
1456   char *           t;
1457
1458   switch (type)
1459     {
1460     case 'f':
1461     case 'F':
1462     case 's':
1463     case 'S':
1464       prec = 2;
1465       break;
1466
1467     case 'd':
1468     case 'D':
1469     case 'r':
1470     case 'R':
1471       prec = 4;
1472       break;
1473
1474    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
1475
1476     default:
1477       * sizeP = 0;
1478       return _("Bad call to md_atof()");
1479     }
1480
1481   t = atof_ieee (input_line_pointer, type, words);
1482   if (t)
1483     input_line_pointer = t;
1484   * sizeP = prec * sizeof (LITTLENUM_TYPE);
1485
1486   for (i = 0; i < prec; i++)
1487     {
1488       md_number_to_chars (litP, (valueT) words[i],
1489                           sizeof (LITTLENUM_TYPE));
1490       litP += sizeof (LITTLENUM_TYPE);
1491     }
1492      
1493   return 0;
1494 }
1495
1496 bfd_boolean
1497 frv_fix_adjustable (fixP)
1498    fixS * fixP;
1499 {
1500   bfd_reloc_code_real_type reloc_type;
1501
1502   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1503     {
1504       const CGEN_INSN *insn = NULL;
1505       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1506       const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1507       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1508     }
1509   else
1510     reloc_type = fixP->fx_r_type;
1511
1512   /* We need the symbol name for the VTABLE entries */
1513   if (   reloc_type == BFD_RELOC_VTABLE_INHERIT
1514       || reloc_type == BFD_RELOC_VTABLE_ENTRY
1515       || reloc_type == BFD_RELOC_FRV_GPREL12
1516       || reloc_type == BFD_RELOC_FRV_GPRELU12)
1517     return 0;
1518
1519   return 1;
1520 }
1521
1522 /* Allow user to set flags bits.  */
1523 void
1524 frv_set_flags (arg)
1525      int arg ATTRIBUTE_UNUSED;
1526 {
1527   flagword new_flags = get_absolute_expression ();
1528   flagword new_mask = ~ (flagword)0;
1529
1530   frv_user_set_flags_p = 1;
1531   if (*input_line_pointer == ',')
1532     {
1533       ++input_line_pointer;
1534       new_mask = get_absolute_expression ();
1535     }
1536
1537   frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1538   bfd_set_private_flags (stdoutput, frv_flags);
1539 }
1540
1541 /* Frv specific function to handle 4 byte initializations for pointers that are
1542    considered 'safe' for use with pic support.  Until frv_frob_file{,_section}
1543    is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1544    BFD_RELOC_32 at that time.  */
1545
1546 void
1547 frv_pic_ptr (nbytes)
1548      int nbytes;
1549 {
1550   expressionS exp;
1551   char *p;
1552
1553   if (nbytes != 4)
1554     abort ();
1555
1556 #ifdef md_flush_pending_output
1557   md_flush_pending_output ();
1558 #endif
1559
1560   if (is_it_end_of_statement ())
1561     {
1562       demand_empty_rest_of_line ();
1563       return;
1564     }
1565
1566 #ifdef md_cons_align
1567   md_cons_align (nbytes);
1568 #endif
1569
1570   do
1571     {
1572       bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
1573       
1574       if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
1575         {
1576           input_line_pointer += 9;
1577           expression (&exp);
1578           if (*input_line_pointer == ')')
1579             input_line_pointer++;
1580           else
1581             as_bad ("missing ')'");
1582           reloc_type = BFD_RELOC_FRV_FUNCDESC;
1583         }
1584       else
1585         expression (&exp);
1586
1587       p = frag_more (4);
1588       memset (p, 0, 4);
1589       fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1590                    reloc_type);
1591     }
1592   while (*input_line_pointer++ == ',');
1593
1594   input_line_pointer--;                 /* Put terminator back into stream. */
1595   demand_empty_rest_of_line ();
1596 }
1597
1598 \f
1599
1600 #ifdef DEBUG
1601 #define DPRINTF1(A)     fprintf (stderr, A)
1602 #define DPRINTF2(A,B)   fprintf (stderr, A, B)
1603 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1604
1605 #else
1606 #define DPRINTF1(A)
1607 #define DPRINTF2(A,B)
1608 #define DPRINTF3(A,B,C)
1609 #endif
1610
1611 /* Go through a the sections looking for relocations that are problematical for
1612    pic.  If not pic, just note that this object can't be linked with pic.  If
1613    it is pic, see if it needs to be marked so that it will be fixed up, or if
1614    not possible, issue an error.  */
1615
1616 static void
1617 frv_frob_file_section (abfd, sec, ptr)
1618      bfd *abfd;
1619      asection *sec;
1620      PTR ptr ATTRIBUTE_UNUSED;
1621 {
1622   segment_info_type *seginfo = seg_info (sec);
1623   fixS *fixp;
1624   CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1625   flagword flags = bfd_get_section_flags (abfd, sec);
1626
1627   /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1628      since we can fix those up by hand.  */
1629   int known_section_p = (sec->name
1630                          && sec->name[0] == '.'
1631                          && ((sec->name[1] == 'c'
1632                               && strcmp (sec->name, ".ctor") == 0)
1633                              || (sec->name[1] == 'd'
1634                                  && strcmp (sec->name, ".dtor") == 0)
1635                              || (sec->name[1] == 'g'
1636                                  && strcmp (sec->name, ".gcc_except_table") == 0)));
1637
1638   DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1639   if ((flags & SEC_ALLOC) == 0)
1640     {
1641       DPRINTF1 ("\tSkipping non-loaded section\n");
1642       return;
1643     }
1644
1645   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1646     {
1647       symbolS *s = fixp->fx_addsy;
1648       bfd_reloc_code_real_type reloc;
1649       int non_pic_p;
1650       int opindex;
1651       const CGEN_OPERAND *operand;
1652       const CGEN_INSN *insn = fixp->fx_cgen.insn;
1653
1654       if (fixp->fx_done)
1655         {
1656           DPRINTF1 ("\tSkipping reloc that has already been done\n");
1657           continue;
1658         }
1659
1660       if (fixp->fx_pcrel)
1661         {
1662           DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1663           continue;
1664         }
1665
1666       if (! s)
1667         {
1668           DPRINTF1 ("\tSkipping reloc without symbol\n");
1669           continue;
1670         }
1671
1672       if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1673         {
1674           opindex = -1;
1675           reloc = fixp->fx_r_type;
1676         }
1677       else
1678         {
1679           opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1680           operand = cgen_operand_lookup_by_num (cd, opindex);
1681           reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1682         }
1683
1684       DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1685
1686       non_pic_p = 0;
1687       switch (reloc)
1688         {
1689         default:
1690           break;
1691
1692         case BFD_RELOC_32:
1693           /* Skip relocations in known sections (.ctors, .dtors, and
1694              .gcc_except_table) since we can fix those up by hand.  Also
1695              skip forward references to constants.  Also skip a difference
1696              of two symbols, which still uses the BFD_RELOC_32 at this
1697              point.  */
1698           if (! known_section_p
1699               && S_GET_SEGMENT (s) != absolute_section
1700               && !fixp->fx_subsy
1701               && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1702             {
1703               non_pic_p = 1;
1704             }
1705           break;
1706
1707           /* FIXME -- should determine if any of the GP relocation really uses
1708              gr16 (which is not pic safe) or not.  Right now, assume if we
1709              aren't being compiled with -mpic, the usage is non pic safe, but
1710              is safe with -mpic.  */
1711         case BFD_RELOC_FRV_GPREL12:
1712         case BFD_RELOC_FRV_GPRELU12:
1713         case BFD_RELOC_FRV_GPREL32:
1714         case BFD_RELOC_FRV_GPRELHI:
1715         case BFD_RELOC_FRV_GPRELLO:
1716           non_pic_p = ! frv_pic_p;
1717           break;
1718
1719         case BFD_RELOC_FRV_LO16:
1720         case BFD_RELOC_FRV_HI16:
1721           if (S_GET_SEGMENT (s) != absolute_section)
1722             non_pic_p = 1;
1723           break;
1724
1725         case BFD_RELOC_VTABLE_INHERIT:
1726         case BFD_RELOC_VTABLE_ENTRY:
1727           non_pic_p = 1;
1728           break;
1729
1730           /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1731              relocation.  */
1732         case BFD_RELOC_CTOR:
1733           fixp->fx_r_type = BFD_RELOC_32;
1734           break;
1735         }
1736
1737       if (non_pic_p)
1738         {
1739           DPRINTF1 (" (Non-pic relocation)\n");
1740           if (frv_pic_p)
1741             as_warn_where (fixp->fx_file, fixp->fx_line,
1742                            _("Relocation %s is not safe for %s"),
1743                            bfd_get_reloc_code_name (reloc), frv_pic_flag);
1744
1745           else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1746             {
1747               frv_flags |= EF_FRV_NON_PIC_RELOCS;
1748               bfd_set_private_flags (abfd, frv_flags);
1749             }
1750         }
1751 #ifdef DEBUG
1752       else
1753         DPRINTF1 ("\n");
1754 #endif
1755     }
1756 }
1757
1758 /* After all of the symbols have been adjusted, go over the file looking
1759    for any relocations that pic won't support.  */
1760
1761 void
1762 frv_frob_file ()
1763 {
1764   bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1765 }
1766
1767 void
1768 frv_frob_label (this_label)
1769     symbolS *this_label;
1770 {
1771   struct vliw_insn_list *vliw_insn_list_entry;
1772
1773   if (frv_mach != bfd_mach_frvtomcat)
1774     return;
1775
1776   if (now_seg != text_section)
1777     return;
1778
1779   vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1780   vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1781   vliw_insn_list_entry->sym  = this_label; 
1782 }
1783
1784 fixS *
1785 frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1786      fragS *              frag;
1787      int                  where;
1788      const CGEN_INSN *    insn;
1789      int                  length;
1790      const CGEN_OPERAND * operand;
1791      int                  opinfo;
1792      expressionS *        exp;
1793 {
1794   fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1795                                            operand, opinfo, exp);
1796
1797   if (frv_mach == bfd_mach_frvtomcat
1798       && current_vliw_insn
1799       && current_vliw_insn->type == VLIW_BRANCH_TYPE
1800       && exp != NULL)
1801     current_vliw_insn->sym = exp->X_add_symbol;
1802     
1803   return fixP;
1804 }