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