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