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