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