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