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