1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2 Copyright 2002, 2003 Free Software Foundation.
4 This file is part of GAS, the GNU Assembler.
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)
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.
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. */
25 #include "opcodes/frv-desc.h"
26 #include "opcodes/frv-opc.h"
29 #include "elf/common.h"
32 /* Structure to hold all of the different components describing
33 an individual instruction. */
36 const CGEN_INSN * insn;
37 const CGEN_INSN * orig_insn;
40 CGEN_INSN_INT buffer [1];
41 #define INSN_VALUE(buf) (*(buf))
43 unsigned char buffer [CGEN_MAX_INSN_SIZE];
44 #define INSN_VALUE(buf) (buf)
49 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
50 int indices [MAX_OPERAND_INSTANCES];
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. */
63 /* We're going to use these in the fr_subtype field to mark
64 whether to keep inserted nops. */
66 #define NOP_KEEP 1 /* Keep these NOPS. */
67 #define NOP_DELETE 2 /* Delete these NOPS. */
70 #define DONT_COUNT FALSE
72 /* A list of insns within a VLIW insn. */
75 /* The type of this insn. */
76 enum vliw_insn_type type;
78 /* The corresponding gas insn information. */
79 const CGEN_INSN *insn;
81 /* For branches and labels, the symbol that is referenced. */
84 /* For branches, the frag containing the single nop that was generated. */
87 /* For branches, the frag containing the double nop that was generated. */
90 /* Pointer to raw data for this insn. */
93 /* Next insn in list. */
94 struct vliw_insn_list *next;
97 static struct vliw_insn_list single_nop_insn = {
98 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
100 static struct vliw_insn_list double_nop_insn = {
101 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
107 struct vliw_insn_list *insn_list;
108 struct vliw_chain *next;
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;
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";
122 static FRV_VLIW vliw;
124 /* Default machine */
126 #ifdef DEFAULT_CPU_FRV
127 #define DEFAULT_MACHINE bfd_mach_frv
128 #define DEFAULT_FLAGS EF_FRV_CPU_GENERIC
131 #ifdef DEFAULT_CPU_FR300
132 #define DEFAULT_MACHINE bfd_mach_fr300
133 #define DEFAULT_FLAGS EF_FRV_CPU_FR300
136 #ifdef DEFAULT_CPU_SIMPLE
137 #define DEFAULT_MACHINE bfd_mach_frvsimple
138 #define DEFAULT_FLAGS EF_FRV_CPU_SIMPLE
141 #ifdef DEFAULT_CPU_TOMCAT
142 #define DEFAULT_MACHINE bfd_mach_frvtomcat
143 #define DEFAULT_FLAGS EF_FRV_CPU_TOMCAT
146 #ifdef DEFAULT_CPU_FR400
147 #define DEFAULT_MACHINE bfd_mach_fr400
148 #define DEFAULT_FLAGS EF_FRV_CPU_FR400
151 #define DEFAULT_MACHINE bfd_mach_fr500
152 #define DEFAULT_FLAGS EF_FRV_CPU_FR500
159 static unsigned long frv_mach = bfd_mach_frv;
161 /* Flags to set in the elf header */
162 static flagword frv_flags = DEFAULT_FLAGS;
164 static int frv_user_set_flags_p = 0;
165 static int frv_pic_p = 0;
166 static const char *frv_pic_flag = (const char *)0;
168 /* Print tomcat-specific debugging info. */
169 static int tomcat_debug = 0;
171 /* Tomcat-specific NOP statistics. */
172 static int tomcat_stats = 0;
173 static int tomcat_doubles = 0;
174 static int tomcat_singles = 0;
176 /* Forward reference to static functions */
177 static void frv_set_flags PARAMS ((int));
178 static void frv_pic_ptr PARAMS ((int));
179 static void frv_frob_file_section PARAMS ((bfd *, asection *, PTR));
181 /* The target specific pseudo-ops which we support. */
182 const pseudo_typeS md_pseudo_table[] =
184 { "eflags", frv_set_flags, 0 },
186 { "picptr", frv_pic_ptr, 4 },
191 #define FRV_SHORTOPTS "G:"
192 const char * md_shortopts = FRV_SHORTOPTS;
194 #define OPTION_GPR_32 (OPTION_MD_BASE)
195 #define OPTION_GPR_64 (OPTION_MD_BASE + 1)
196 #define OPTION_FPR_32 (OPTION_MD_BASE + 2)
197 #define OPTION_FPR_64 (OPTION_MD_BASE + 3)
198 #define OPTION_SOFT_FLOAT (OPTION_MD_BASE + 4)
199 #define OPTION_DWORD_YES (OPTION_MD_BASE + 5)
200 #define OPTION_DWORD_NO (OPTION_MD_BASE + 6)
201 #define OPTION_DOUBLE (OPTION_MD_BASE + 7)
202 #define OPTION_NO_DOUBLE (OPTION_MD_BASE + 8)
203 #define OPTION_MEDIA (OPTION_MD_BASE + 9)
204 #define OPTION_NO_MEDIA (OPTION_MD_BASE + 10)
205 #define OPTION_CPU (OPTION_MD_BASE + 11)
206 #define OPTION_PIC (OPTION_MD_BASE + 12)
207 #define OPTION_BIGPIC (OPTION_MD_BASE + 13)
208 #define OPTION_LIBPIC (OPTION_MD_BASE + 14)
209 #define OPTION_MULADD (OPTION_MD_BASE + 15)
210 #define OPTION_NO_MULADD (OPTION_MD_BASE + 16)
211 #define OPTION_TOMCAT_DEBUG (OPTION_MD_BASE + 17)
212 #define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
213 #define OPTION_PACK (OPTION_MD_BASE + 19)
214 #define OPTION_NO_PACK (OPTION_MD_BASE + 20)
216 struct option md_longopts[] =
218 { "mgpr-32", no_argument, NULL, OPTION_GPR_32 },
219 { "mgpr-64", no_argument, NULL, OPTION_GPR_64 },
220 { "mfpr-32", no_argument, NULL, OPTION_FPR_32 },
221 { "mfpr-64", no_argument, NULL, OPTION_FPR_64 },
222 { "mhard-float", no_argument, NULL, OPTION_FPR_64 },
223 { "msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT },
224 { "mdword", no_argument, NULL, OPTION_DWORD_YES },
225 { "mno-dword", no_argument, NULL, OPTION_DWORD_NO },
226 { "mdouble", no_argument, NULL, OPTION_DOUBLE },
227 { "mno-double", no_argument, NULL, OPTION_NO_DOUBLE },
228 { "mmedia", no_argument, NULL, OPTION_MEDIA },
229 { "mno-media", no_argument, NULL, OPTION_NO_MEDIA },
230 { "mcpu", required_argument, NULL, OPTION_CPU },
231 { "mpic", no_argument, NULL, OPTION_PIC },
232 { "mPIC", no_argument, NULL, OPTION_BIGPIC },
233 { "mlibrary-pic", no_argument, NULL, OPTION_LIBPIC },
234 { "mmuladd", no_argument, NULL, OPTION_MULADD },
235 { "mno-muladd", no_argument, NULL, OPTION_NO_MULADD },
236 { "mtomcat-debug", no_argument, NULL, OPTION_TOMCAT_DEBUG },
237 { "mtomcat-stats", no_argument, NULL, OPTION_TOMCAT_STATS },
238 { "mpack", no_argument, NULL, OPTION_PACK },
239 { "mno-pack", no_argument, NULL, OPTION_NO_PACK },
240 { NULL, no_argument, NULL, 0 },
243 size_t md_longopts_size = sizeof (md_longopts);
245 /* What value to give to bfd_set_gp_size. */
246 static int g_switch_value = 8;
249 md_parse_option (c, arg)
259 g_switch_value = atoi (arg);
260 if (! g_switch_value)
261 frv_flags |= EF_FRV_G0;
265 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
269 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
273 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
277 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
280 case OPTION_SOFT_FLOAT:
281 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
284 case OPTION_DWORD_YES:
285 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
288 case OPTION_DWORD_NO:
289 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
293 frv_flags |= EF_FRV_DOUBLE;
296 case OPTION_NO_DOUBLE:
297 frv_flags &= ~EF_FRV_DOUBLE;
301 frv_flags |= EF_FRV_MEDIA;
304 case OPTION_NO_MEDIA:
305 frv_flags &= ~EF_FRV_MEDIA;
309 frv_flags |= EF_FRV_MULADD;
312 case OPTION_NO_MULADD:
313 frv_flags &= ~EF_FRV_MULADD;
317 frv_flags &= ~EF_FRV_NOPACK;
321 frv_flags |= EF_FRV_NOPACK;
327 int cpu_flags = EF_FRV_CPU_GENERIC;
329 /* Identify the processor type */
331 if (strcmp (p, "frv") == 0)
333 cpu_flags = EF_FRV_CPU_GENERIC;
334 frv_mach = bfd_mach_frv;
337 else if (strcmp (p, "fr500") == 0)
339 cpu_flags = EF_FRV_CPU_FR500;
340 frv_mach = bfd_mach_fr500;
343 else if (strcmp (p, "fr400") == 0)
345 cpu_flags = EF_FRV_CPU_FR400;
346 frv_mach = bfd_mach_fr400;
349 else if (strcmp (p, "fr300") == 0)
351 cpu_flags = EF_FRV_CPU_FR300;
352 frv_mach = bfd_mach_fr300;
355 else if (strcmp (p, "simple") == 0)
357 cpu_flags = EF_FRV_CPU_SIMPLE;
358 frv_mach = bfd_mach_frvsimple;
359 frv_flags |= EF_FRV_NOPACK;
362 else if (strcmp (p, "tomcat") == 0)
364 cpu_flags = EF_FRV_CPU_TOMCAT;
365 frv_mach = bfd_mach_frvtomcat;
370 as_fatal ("Unknown cpu -mcpu=%s", arg);
374 frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
379 frv_flags |= EF_FRV_PIC;
381 frv_pic_flag = "-fpic";
385 frv_flags |= EF_FRV_BIGPIC;
387 frv_pic_flag = "-fPIC";
391 frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
393 frv_pic_flag = "-mlibrary-pic";
397 case OPTION_TOMCAT_DEBUG:
401 case OPTION_TOMCAT_STATS:
410 md_show_usage (stream)
413 fprintf (stream, _("FRV specific command line options:\n"));
414 fprintf (stream, _("-G n Data >= n bytes is in small data area\n"));
415 fprintf (stream, _("-mgpr-32 Note 32 gprs are used\n"));
416 fprintf (stream, _("-mgpr-64 Note 64 gprs are used\n"));
417 fprintf (stream, _("-mfpr-32 Note 32 fprs are used\n"));
418 fprintf (stream, _("-mfpr-64 Note 64 fprs are used\n"));
419 fprintf (stream, _("-msoft-float Note software fp is used\n"));
420 fprintf (stream, _("-mdword Note stack is aligned to a 8 byte boundary\n"));
421 fprintf (stream, _("-mno-dword Note stack is aligned to a 4 byte boundary\n"));
422 fprintf (stream, _("-mdouble Note fp double insns are used\n"));
423 fprintf (stream, _("-mmedia Note media insns are used\n"));
424 fprintf (stream, _("-mmuladd Note multiply add/subtract insns are used\n"));
425 fprintf (stream, _("-mpack Note instructions are packed\n"));
426 fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
427 fprintf (stream, _("-mpic Note small position independent code\n"));
428 fprintf (stream, _("-mPIC Note large position independent code\n"));
429 fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
430 fprintf (stream, _("-mcpu={fr500|fr400|fr300|frv|simple|tomcat}\n"));
431 fprintf (stream, _(" Record the cpu type\n"));
432 fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
433 fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
440 /* Initialize the `cgen' interface. */
442 /* Set the machine number and endian. */
443 gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
444 CGEN_CPU_OPEN_ENDIAN,
447 frv_cgen_init_asm (gas_cgen_cpu_desc);
449 /* This is a callback from cgen to gas to parse operands. */
450 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
452 /* Set the ELF flags if desired. */
454 bfd_set_private_flags (stdoutput, frv_flags);
456 /* Set the machine type */
457 bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
459 /* Set up gp size so we can put local common items in .sbss */
460 bfd_set_gp_size (stdoutput, g_switch_value);
462 frv_vliw_reset (& vliw, frv_mach, frv_flags);
467 struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
469 struct vliw_insn_list *
470 frv_insert_vliw_insn (count)
473 struct vliw_insn_list *vliw_insn_list_entry;
474 struct vliw_chain *vliw_chain_entry;
476 if (current_vliw_chain == NULL)
478 vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
479 vliw_chain_entry->insn_count = 0;
480 vliw_chain_entry->insn_list = NULL;
481 vliw_chain_entry->next = NULL;
482 vliw_chain_entry->num = chain_num++;
485 vliw_chain_top = vliw_chain_entry;
486 current_vliw_chain = vliw_chain_entry;
487 if (previous_vliw_chain)
488 previous_vliw_chain->next = vliw_chain_entry;
491 vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
492 vliw_insn_list_entry->type = VLIW_GENERIC_TYPE;
493 vliw_insn_list_entry->insn = NULL;
494 vliw_insn_list_entry->sym = NULL;
495 vliw_insn_list_entry->snop_frag = NULL;
496 vliw_insn_list_entry->dnop_frag = NULL;
497 vliw_insn_list_entry->next = NULL;
500 current_vliw_chain->insn_count++;
502 if (current_vliw_insn)
503 current_vliw_insn->next = vliw_insn_list_entry;
504 current_vliw_insn = vliw_insn_list_entry;
506 if (!current_vliw_chain->insn_list)
507 current_vliw_chain->insn_list = current_vliw_insn;
509 return vliw_insn_list_entry;
512 /* Identify the following cases:
514 1) A VLIW insn that contains both a branch and the branch destination.
515 This requires the insertion of two vliw instructions before the
516 branch. The first consists of two nops. The second consists of
519 2) A single instruction VLIW insn which is the destination of a branch
520 that is in the next VLIW insn. This requires the insertion of a vliw
521 insn containing two nops before the branch.
523 3) A double instruction VLIW insn which contains the destination of a
524 branch that is in the next VLIW insn. This requires the insertion of
525 a VLIW insn containing a single nop before the branch.
527 4) A single instruction VLIW insn which contains branch destination (x),
528 followed by a single instruction VLIW insn which does not contain
529 the branch to (x), followed by a VLIW insn which does contain the branch
530 to (x). This requires the insertion of a VLIW insn containing a single
531 nop before the VLIW instruction containing the branch.
534 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
535 #define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
536 #define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
538 /* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
540 static struct vliw_insn_list *frv_find_in_vliw
541 PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
543 static struct vliw_insn_list *
544 frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
545 enum vliw_insn_type vliw_insn_type;
546 struct vliw_chain *this_chain;
550 struct vliw_insn_list *the_insn;
555 for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
557 if (the_insn->type == vliw_insn_type
558 && the_insn->sym == label_sym)
567 /* A Vliw insn containing a single nop insn. */
570 /* A Vliw insn containing two nop insns. */
573 /* Two vliw insns. The first containing two nop insns.
574 The second contain a single nop insn. */
575 VLIW_DOUBLE_THEN_SINGLE_NOP
578 static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
581 frv_debug_tomcat (start_chain)
582 struct vliw_chain *start_chain;
584 struct vliw_chain *this_chain;
585 struct vliw_insn_list *this_insn;
588 for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
590 fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
592 for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
594 if (this_insn->type == VLIW_LABEL_TYPE)
595 fprintf (stderr, "Label Value: %d\n", (int) this_insn->sym);
596 else if (this_insn->type == VLIW_BRANCH_TYPE)
597 fprintf (stderr, "%s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
598 else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
599 fprintf (stderr, "nop'd %s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
600 else if (this_insn->type == VLIW_NOP_TYPE)
601 fprintf (stderr, "Nop\n");
603 fprintf (stderr, " %s\n", this_insn->insn->base->name);
608 static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
611 frv_adjust_vliw_count (this_chain)
612 struct vliw_chain *this_chain;
614 struct vliw_insn_list *this_insn;
616 this_chain->insn_count = 0;
618 for (this_insn = this_chain->insn_list;
620 this_insn = this_insn->next)
622 if (this_insn->type != VLIW_LABEL_TYPE)
623 this_chain->insn_count++;
628 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
629 Rechain the vliw insn. */
631 static struct vliw_chain *frv_tomcat_shuffle
632 PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
634 static struct vliw_chain *
635 frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
636 enum vliw_nop_type this_nop_type;
637 struct vliw_chain *vliw_to_split;
638 struct vliw_insn_list *insert_before_insn;
641 bfd_boolean pack_prev = FALSE;
642 struct vliw_chain *return_me = NULL;
643 struct vliw_insn_list *prev_insn = NULL;
644 struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
646 struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
647 struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
648 struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
649 struct vliw_chain *curr_vliw = vliw_chain_top;
650 struct vliw_chain *prev_vliw = NULL;
652 while (curr_insn && curr_insn != insert_before_insn)
654 /* We can't set the packing bit on a label. If we have the case
658 branch that needs nops
659 Then don't set pack bit later. */
661 if (curr_insn->type != VLIW_LABEL_TYPE)
663 prev_insn = curr_insn;
664 curr_insn = curr_insn->next;
667 while (curr_vliw && curr_vliw != vliw_to_split)
669 prev_vliw = curr_vliw;
670 curr_vliw = curr_vliw->next;
673 switch (this_nop_type)
675 case VLIW_SINGLE_NOP:
678 /* Branch is first, Insert the NOP prior to this vliw insn. */
680 prev_vliw->next = single_nop;
682 vliw_chain_top = single_nop;
683 single_nop->next = vliw_to_split;
684 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
685 return_me = vliw_to_split;
689 /* Set the packing bit on the previous insn. */
692 unsigned char *buffer = prev_insn->address;
695 /* The branch is in the middle. Split this vliw insn into first
696 and second parts. Insert the NOP inbetween. */
698 second_part->insn_list = insert_before_insn;
699 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
700 second_part->next = vliw_to_split->next;
701 frv_adjust_vliw_count (second_part);
703 single_nop->next = second_part;
705 vliw_to_split->next = single_nop;
706 prev_insn->next = NULL;
708 return_me = second_part;
709 frv_adjust_vliw_count (vliw_to_split);
713 case VLIW_DOUBLE_NOP:
716 /* Branch is first, Insert the NOP prior to this vliw insn. */
718 prev_vliw->next = double_nop;
720 vliw_chain_top = double_nop;
722 double_nop->next = vliw_to_split;
723 return_me = vliw_to_split;
724 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
728 /* Set the packing bit on the previous insn. */
731 unsigned char *buffer = prev_insn->address;
735 /* The branch is in the middle. Split this vliw insn into first
736 and second parts. Insert the NOP inbetween. */
737 second_part->insn_list = insert_before_insn;
738 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
739 second_part->next = vliw_to_split->next;
740 frv_adjust_vliw_count (second_part);
742 double_nop->next = second_part;
744 vliw_to_split->next = single_nop;
745 prev_insn->next = NULL;
746 frv_adjust_vliw_count (vliw_to_split);
748 return_me = second_part;
752 case VLIW_DOUBLE_THEN_SINGLE_NOP:
753 double_nop->next = single_nop;
754 double_nop->insn_count = 2;
755 double_nop->insn_list = &double_nop_insn;
756 single_nop->insn_count = 1;
757 single_nop->insn_list = &single_nop_insn;
761 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
762 the nops prior to this vliw. */
764 prev_vliw->next = double_nop;
766 vliw_chain_top = double_nop;
768 single_nop->next = vliw_to_split;
769 return_me = vliw_to_split;
770 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
774 /* Set the packing bit on the previous insn. */
777 unsigned char *buffer = prev_insn->address;
781 /* The branch is in the middle of this vliw insn. Split into first and
782 second parts. Insert the nop vliws in between. */
783 second_part->insn_list = insert_before_insn;
784 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
785 second_part->next = vliw_to_split->next;
786 frv_adjust_vliw_count (second_part);
788 single_nop->next = second_part;
790 vliw_to_split->next = double_nop;
791 prev_insn->next = NULL;
792 frv_adjust_vliw_count (vliw_to_split);
794 return_me = second_part;
802 static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
805 frv_tomcat_analyze_vliw_chains ()
807 struct vliw_chain *vliw1 = NULL;
808 struct vliw_chain *vliw2 = NULL;
809 struct vliw_chain *vliw3 = NULL;
811 struct vliw_insn_list *this_insn = NULL;
812 struct vliw_insn_list *temp_insn = NULL;
814 /* We potentially need to look at three VLIW insns to determine if the
815 workaround is required. Set them up. Ignore existing nops during analysis. */
817 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
818 if (VLIW1 && VLIW1->next) \
819 VLIW2 = VLIW1->next; \
822 if (VLIW2 && VLIW2->next) \
823 VLIW3 = VLIW2->next; \
827 vliw1 = vliw_chain_top;
831 FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
836 if (vliw1->insn_count == 1)
838 /* check vliw1 for a label. */
839 if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
841 temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
844 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
845 temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
852 && vliw2->insn_count == 1
853 && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
855 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
856 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
864 if (vliw1->insn_count == 2)
866 struct vliw_insn_list *this_insn;
868 /* check vliw1 for a label. */
869 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
871 if (this_insn->type == VLIW_LABEL_TYPE)
873 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
875 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
876 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
886 /* Examine each insn in this VLIW. Look for the workaround criteria. */
887 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
889 /* Don't look at labels or nops. */
891 && (this_insn->type == VLIW_LABEL_TYPE
892 || this_insn->type == VLIW_NOP_TYPE
893 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
894 this_insn = this_insn->next;
902 if (frv_is_branch_insn (this_insn->insn))
904 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
906 /* Insert [nop/nop] [nop] before branch. */
907 this_insn->snop_frag->fr_subtype = NOP_KEEP;
908 this_insn->dnop_frag->fr_subtype = NOP_KEEP;
909 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
916 /* This vliw insn checks out okay. Take a look at the next one. */
922 frv_tomcat_workaround ()
924 if (frv_mach != bfd_mach_frvtomcat)
928 frv_debug_tomcat (vliw_chain_top);
930 frv_tomcat_analyze_vliw_chains ();
934 fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
935 fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
945 int packing_constraint;
946 finished_insnS finished_insn;
947 fragS *double_nop_frag = NULL;
948 fragS *single_nop_frag = NULL;
949 struct vliw_insn_list *vliw_insn_list_entry = NULL;
951 /* Initialize GAS's cgen interface for a new instruction. */
952 gas_cgen_init_parse ();
954 insn.insn = frv_cgen_assemble_insn
955 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
963 /* If the cpu is tomcat, then we need to insert nops to workaround
964 hardware limitations. We need to keep track of each vliw unit
965 and examine the length of the unit and the individual insns
966 within the unit to determine the number and location of the
968 if (frv_mach == bfd_mach_frvtomcat)
970 /* If we've just finished a VLIW insn OR this is a branch,
971 then start up a new frag. Fill it with nops. We will get rid
972 of those that are not required after we've seen all of the
973 instructions but before we start resolving fixups. */
974 if ( !FRV_IS_NOP (insn)
975 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
979 frag_wane (frag_now);
981 double_nop_frag = frag_now;
982 buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
983 md_number_to_chars (buffer, FRV_NOP_PACK, 4);
984 md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
986 frag_wane (frag_now);
988 single_nop_frag = frag_now;
989 buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
990 md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
993 vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
994 vliw_insn_list_entry->insn = insn.insn;
995 if (frv_is_branch_insn (insn.insn))
996 vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
998 if ( !FRV_IS_NOP (insn)
999 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1001 vliw_insn_list_entry->snop_frag = single_nop_frag;
1002 vliw_insn_list_entry->dnop_frag = double_nop_frag;
1006 /* Make sure that this insn does not violate the VLIW packing constraints. */
1007 /* -mno-pack disallows any packing whatsoever. */
1008 if (frv_flags & EF_FRV_NOPACK)
1010 if (! insn.fields.f_pack)
1012 as_bad (_("VLIW packing used for -mno-pack"));
1016 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1017 instructions, don't do vliw checking. */
1018 else if (frv_mach != bfd_mach_frv)
1020 packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1021 if (insn.fields.f_pack)
1022 frv_vliw_reset (& vliw, frv_mach, frv_flags);
1023 if (packing_constraint)
1025 as_bad (_("VLIW packing constraint violation"));
1030 /* Doesn't really matter what we pass for RELAX_P here. */
1031 gas_cgen_finish_insn (insn.insn, insn.buffer,
1032 CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1035 /* If the cpu is tomcat, then we need to insert nops to workaround
1036 hardware limitations. We need to keep track of each vliw unit
1037 and examine the length of the unit and the individual insns
1038 within the unit to determine the number and location of the
1040 if (frv_mach == bfd_mach_frvtomcat)
1042 if (vliw_insn_list_entry)
1043 vliw_insn_list_entry->address = finished_insn.addr;
1047 if (insn.fields.f_pack)
1049 /* We've completed a VLIW insn. */
1050 previous_vliw_chain = current_vliw_chain;
1051 current_vliw_chain = NULL;
1052 current_vliw_insn = NULL;
1057 /* The syntax in the manual says constants begin with '#'.
1058 We just ignore it. */
1061 md_operand (expressionP)
1062 expressionS * expressionP;
1064 if (* input_line_pointer == '#')
1066 input_line_pointer ++;
1067 expression (expressionP);
1072 md_section_align (segment, size)
1076 int align = bfd_get_section_alignment (stdoutput, segment);
1077 return ((size + (1 << align) - 1) & (-1 << align));
1081 md_undefined_symbol (name)
1082 char * name ATTRIBUTE_UNUSED;
1087 /* Interface to relax_segment. */
1089 /* FIXME: Build table by hand, get it working, then machine generate. */
1090 const relax_typeS md_relax_table[] =
1093 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1094 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1095 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1099 frv_relax_frag (fragP, stretch)
1100 fragS *fragP ATTRIBUTE_UNUSED;
1101 long stretch ATTRIBUTE_UNUSED;
1106 /* Return an initial guess of the length by which a fragment must grow to
1107 hold a branch to reach its destination.
1108 Also updates fr_type/fr_subtype as necessary.
1110 Called just before doing relaxation.
1111 Any symbol that is now undefined will not become defined.
1112 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1113 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1114 Although it may not be explicit in the frag, pretend fr_var starts with a
1118 md_estimate_size_before_relax (fragP, segment)
1120 segT segment ATTRIBUTE_UNUSED;
1122 switch (fragP->fr_subtype)
1125 return fragP->fr_var;
1133 /* *fragP has been relaxed to its final size, and now needs to have
1134 the bytes inside it modified to conform to the new size.
1136 Called after relaxation is finished.
1137 fragP->fr_type == rs_machine_dependent.
1138 fragP->fr_subtype is the subtype of what the address relaxed to. */
1141 md_convert_frag (abfd, sec, fragP)
1142 bfd * abfd ATTRIBUTE_UNUSED;
1143 segT sec ATTRIBUTE_UNUSED;
1146 switch (fragP->fr_subtype)
1153 fragP->fr_fix = fragP->fr_var;
1159 /* Functions concerning relocs. */
1161 /* The location from which a PC relative jump should be calculated,
1162 given a PC relative reloc. */
1165 md_pcrel_from_section (fixP, sec)
1169 if (fixP->fx_addsy != (symbolS *) NULL
1170 && (! S_IS_DEFINED (fixP->fx_addsy)
1171 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
1173 /* The symbol is undefined (or is defined but not in this section).
1174 Let the linker figure it out. */
1178 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1181 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1182 Returns BFD_RELOC_NONE if no reloc type can be found.
1183 *FIXP may be modified if desired. */
1185 bfd_reloc_code_real_type
1186 md_cgen_lookup_reloc (insn, operand, fixP)
1187 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
1188 const CGEN_OPERAND * operand;
1191 switch (operand->type)
1193 case FRV_OPERAND_LABEL16:
1194 fixP->fx_pcrel = TRUE;
1195 return BFD_RELOC_FRV_LABEL16;
1197 case FRV_OPERAND_LABEL24:
1198 fixP->fx_pcrel = TRUE;
1199 return BFD_RELOC_FRV_LABEL24;
1201 case FRV_OPERAND_UHI16:
1202 case FRV_OPERAND_ULO16:
1203 case FRV_OPERAND_SLO16:
1205 /* The relocation type should be recorded in opinfo */
1206 if (fixP->fx_cgen.opinfo != 0)
1207 return fixP->fx_cgen.opinfo;
1210 case FRV_OPERAND_D12:
1211 case FRV_OPERAND_S12:
1212 return BFD_RELOC_FRV_GPREL12;
1214 case FRV_OPERAND_U12:
1215 return BFD_RELOC_FRV_GPRELU12;
1220 return BFD_RELOC_NONE;
1224 /* See whether we need to force a relocation into the output file.
1225 This is used to force out switch and PC relative relocations when
1229 frv_force_relocation (fix)
1232 if (fix->fx_r_type == BFD_RELOC_FRV_GPREL12
1233 || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
1236 return generic_force_reloc (fix);
1239 /* Write a value out to the object file, using the appropriate endianness. */
1242 frv_md_number_to_chars (buf, val, n)
1247 number_to_chars_bigendian (buf, val, n);
1250 /* Turn a string in input_line_pointer into a floating point constant of type
1251 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1252 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1255 /* Equal to MAX_PRECISION in atof-ieee.c */
1256 #define MAX_LITTLENUMS 6
1259 md_atof (type, litP, sizeP)
1266 LITTLENUM_TYPE words [MAX_LITTLENUMS];
1285 /* FIXME: Some targets allow other format chars for bigger sizes here. */
1289 return _("Bad call to md_atof()");
1292 t = atof_ieee (input_line_pointer, type, words);
1294 input_line_pointer = t;
1295 * sizeP = prec * sizeof (LITTLENUM_TYPE);
1297 for (i = 0; i < prec; i++)
1299 md_number_to_chars (litP, (valueT) words[i],
1300 sizeof (LITTLENUM_TYPE));
1301 litP += sizeof (LITTLENUM_TYPE);
1308 frv_fix_adjustable (fixP)
1311 bfd_reloc_code_real_type reloc_type;
1313 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1315 const CGEN_INSN *insn = NULL;
1316 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1317 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1318 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1321 reloc_type = fixP->fx_r_type;
1323 /* We need the symbol name for the VTABLE entries */
1324 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1325 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1326 || reloc_type == BFD_RELOC_FRV_GPREL12
1327 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1333 /* Allow user to set flags bits. */
1336 int arg ATTRIBUTE_UNUSED;
1338 flagword new_flags = get_absolute_expression ();
1339 flagword new_mask = ~ (flagword)0;
1341 frv_user_set_flags_p = 1;
1342 if (*input_line_pointer == ',')
1344 ++input_line_pointer;
1345 new_mask = get_absolute_expression ();
1348 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1349 bfd_set_private_flags (stdoutput, frv_flags);
1352 /* Frv specific function to handle 4 byte initializations for pointers that are
1353 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1354 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1355 BFD_RELOC_32 at that time. */
1358 frv_pic_ptr (nbytes)
1367 #ifdef md_flush_pending_output
1368 md_flush_pending_output ();
1371 if (is_it_end_of_statement ())
1373 demand_empty_rest_of_line ();
1377 #ifdef md_cons_align
1378 md_cons_align (nbytes);
1387 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1390 while (*input_line_pointer++ == ',');
1392 input_line_pointer--; /* Put terminator back into stream. */
1393 demand_empty_rest_of_line ();
1399 #define DPRINTF1(A) fprintf (stderr, A)
1400 #define DPRINTF2(A,B) fprintf (stderr, A, B)
1401 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1405 #define DPRINTF2(A,B)
1406 #define DPRINTF3(A,B,C)
1409 /* Go through a the sections looking for relocations that are problematical for
1410 pic. If not pic, just note that this object can't be linked with pic. If
1411 it is pic, see if it needs to be marked so that it will be fixed up, or if
1412 not possible, issue an error. */
1415 frv_frob_file_section (abfd, sec, ptr)
1418 PTR ptr ATTRIBUTE_UNUSED;
1420 segment_info_type *seginfo = seg_info (sec);
1422 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1423 flagword flags = bfd_get_section_flags (abfd, sec);
1425 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1426 since we can fix those up by hand. */
1427 int known_section_p = (sec->name
1428 && sec->name[0] == '.'
1429 && ((sec->name[1] == 'c'
1430 && strcmp (sec->name, ".ctor") == 0)
1431 || (sec->name[1] == 'd'
1432 && strcmp (sec->name, ".dtor") == 0)
1433 || (sec->name[1] == 'g'
1434 && strcmp (sec->name, ".gcc_except_table") == 0)));
1436 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1437 if ((flags & SEC_ALLOC) == 0)
1439 DPRINTF1 ("\tSkipping non-loaded section\n");
1443 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1445 symbolS *s = fixp->fx_addsy;
1446 bfd_reloc_code_real_type reloc;
1449 const CGEN_OPERAND *operand;
1450 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1454 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1460 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1466 DPRINTF1 ("\tSkipping reloc without symbol\n");
1470 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1473 reloc = fixp->fx_r_type;
1477 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1478 operand = cgen_operand_lookup_by_num (cd, opindex);
1479 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1482 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1491 /* Skip relocations in known sections (.ctors, .dtors, and
1492 .gcc_except_table) since we can fix those up by hand. Also
1493 skip forward references to constants. Also skip a difference
1494 of two symbols, which still uses the BFD_RELOC_32 at this
1496 if (! known_section_p
1497 && S_GET_SEGMENT (s) != absolute_section
1499 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1505 /* FIXME -- should determine if any of the GP relocation really uses
1506 gr16 (which is not pic safe) or not. Right now, assume if we
1507 aren't being compiled with -mpic, the usage is non pic safe, but
1508 is safe with -mpic. */
1509 case BFD_RELOC_FRV_GPREL12:
1510 case BFD_RELOC_FRV_GPRELU12:
1511 case BFD_RELOC_FRV_GPREL32:
1512 case BFD_RELOC_FRV_GPRELHI:
1513 case BFD_RELOC_FRV_GPRELLO:
1514 non_pic_p = ! frv_pic_p;
1517 case BFD_RELOC_FRV_LO16:
1518 case BFD_RELOC_FRV_HI16:
1519 if (S_GET_SEGMENT (s) != absolute_section)
1523 case BFD_RELOC_VTABLE_INHERIT:
1524 case BFD_RELOC_VTABLE_ENTRY:
1528 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1530 case BFD_RELOC_CTOR:
1531 fixp->fx_r_type = BFD_RELOC_32;
1537 DPRINTF1 (" (Non-pic relocation)\n");
1539 as_warn_where (fixp->fx_file, fixp->fx_line,
1540 _("Relocation %s is not safe for %s"),
1541 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1543 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1545 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1546 bfd_set_private_flags (abfd, frv_flags);
1556 /* After all of the symbols have been adjusted, go over the file looking
1557 for any relocations that pic won't support. */
1562 bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1566 frv_frob_label (this_label)
1567 symbolS *this_label;
1569 struct vliw_insn_list *vliw_insn_list_entry;
1571 if (frv_mach != bfd_mach_frvtomcat)
1574 if (now_seg != text_section)
1577 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1578 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1579 vliw_insn_list_entry->sym = this_label;
1583 frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1586 const CGEN_INSN * insn;
1588 const CGEN_OPERAND * operand;
1592 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1593 operand, opinfo, exp);
1595 if (frv_mach == bfd_mach_frvtomcat
1596 && current_vliw_insn
1597 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1599 current_vliw_insn->sym = exp->X_add_symbol;