]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gas/config/tc-fr30.c
change BFD_RELOC_FR30_32 to BFD_RELOC_FR30_48
[thirdparty/binutils-gdb.git] / gas / config / tc-fr30.c
1 /* tc-fr30.c -- Assembler for the Fujitsu FR30.
2 Copyright (C) 1998 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 <ctype.h>
23 #include "as.h"
24 #include "subsegs.h"
25 #include "symcat.h"
26 #include "cgen-opc.h"
27 #include "cgen.h"
28
29 /* Structure to hold all of the different components describing
30 an individual instruction. */
31 typedef struct
32 {
33 const CGEN_INSN * insn;
34 const CGEN_INSN * orig_insn;
35 CGEN_FIELDS fields;
36 #if CGEN_INT_INSN_P
37 CGEN_INSN_INT buffer [1];
38 #define INSN_VALUE(buf) (*(buf))
39 #else
40 unsigned char buffer [CGEN_MAX_INSN_SIZE];
41 #define INSN_VALUE(buf) (buf)
42 #endif
43 char * addr;
44 fragS * frag;
45 int num_fixups;
46 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
47 int indices [MAX_OPERAND_INSTANCES];
48 }
49 fr30_insn;
50
51 const char comment_chars[] = ";";
52 const char line_comment_chars[] = "#";
53 const char line_separator_chars[] = "";
54 const char EXP_CHARS[] = "eE";
55 const char FLT_CHARS[] = "dD";
56 \f
57 #define FR30_SHORTOPTS ""
58 const char * md_shortopts = FR30_SHORTOPTS;
59
60 struct option md_longopts[] =
61 {
62 {NULL, no_argument, NULL, 0}
63 };
64 size_t md_longopts_size = sizeof (md_longopts);
65
66 int
67 md_parse_option (c, arg)
68 int c;
69 char * arg;
70 {
71 switch (c)
72 {
73 default:
74 return 0;
75 }
76 return 1;
77 }
78
79 void
80 md_show_usage (stream)
81 FILE * stream;
82 {
83 fprintf (stream, _(" FR30 specific command line options:\n"));
84 }
85
86 /* The target specific pseudo-ops which we support. */
87 const pseudo_typeS md_pseudo_table[] =
88 {
89 { "word", cons, 4 },
90 { NULL, NULL, 0 }
91 };
92
93 \f
94 void
95 md_begin ()
96 {
97 flagword applicable;
98 segT seg;
99 subsegT subseg;
100
101 /* Initialize the `cgen' interface. */
102
103 /* Set the machine number and endian. */
104 gas_cgen_opcode_desc = fr30_cgen_opcode_open (bfd_mach_fr30, CGEN_ENDIAN_BIG);
105 fr30_cgen_init_asm (gas_cgen_opcode_desc);
106
107 /* This is a callback from cgen to gas to parse operands. */
108 cgen_set_parse_operand_fn (gas_cgen_opcode_desc, gas_cgen_parse_operand);
109 }
110
111 void
112 md_assemble (str)
113 char * str;
114 {
115 fr30_insn insn;
116 char * errmsg;
117 char * str2 = NULL;
118
119 /* Initialize GAS's cgen interface for a new instruction. */
120 gas_cgen_init_parse ();
121
122 insn.insn = fr30_cgen_assemble_insn
123 (gas_cgen_opcode_desc, str, & insn.fields, insn.buffer, & errmsg);
124
125 if (!insn.insn)
126 {
127 as_bad (errmsg);
128 return;
129 }
130
131 /* Doesn't really matter what we pass for RELAX_P here. */
132 gas_cgen_finish_insn (insn.insn, insn.buffer,
133 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
134 }
135
136 /* The syntax in the manual says constants begin with '#'.
137 We just ignore it. */
138
139 void
140 md_operand (expressionP)
141 expressionS * expressionP;
142 {
143 if (* input_line_pointer == '#')
144 {
145 input_line_pointer ++;
146 expression (expressionP);
147 }
148 }
149
150 valueT
151 md_section_align (segment, size)
152 segT segment;
153 valueT size;
154 {
155 int align = bfd_get_section_alignment (stdoutput, segment);
156 return ((size + (1 << align) - 1) & (-1 << align));
157 }
158
159 symbolS *
160 md_undefined_symbol (name)
161 char * name;
162 {
163 return 0;
164 }
165 \f
166 /* Interface to relax_segment. */
167
168 /* FIXME: Build table by hand, get it working, then machine generate. */
169
170 const relax_typeS md_relax_table[] =
171 {
172 /* The fields are:
173 1) most positive reach of this state,
174 2) most negative reach of this state,
175 3) how many bytes this mode will add to the size of the current frag
176 4) which index into the table to try if we can't fit into this one. */
177
178 /* The first entry must be unused because an `rlx_more' value of zero ends
179 each list. */
180 {1, 1, 0, 0},
181
182 /* The displacement used by GAS is from the end of the 2 byte insn,
183 so we subtract 2 from the following. */
184 /* 16 bit insn, 8 bit disp -> 10 bit range.
185 This doesn't handle a branch in the right slot at the border:
186 the "& -4" isn't taken into account. It's not important enough to
187 complicate things over it, so we subtract an extra 2 (or + 2 in -ve
188 case). */
189 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
190 /* 32 bit insn, 24 bit disp -> 26 bit range. */
191 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
192 /* Same thing, but with leading nop for alignment. */
193 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
194 };
195
196 long
197 fr30_relax_frag (fragP, stretch)
198 fragS * fragP;
199 long stretch;
200 {
201 /* Address of branch insn. */
202 long address = fragP->fr_address + fragP->fr_fix - 2;
203 long growth = 0;
204
205 /* Keep 32 bit insns aligned on 32 bit boundaries. */
206 if (fragP->fr_subtype == 2)
207 {
208 if ((address & 3) != 0)
209 {
210 fragP->fr_subtype = 3;
211 growth = 2;
212 }
213 }
214 else if (fragP->fr_subtype == 3)
215 {
216 if ((address & 3) == 0)
217 {
218 fragP->fr_subtype = 2;
219 growth = -2;
220 }
221 }
222 else
223 {
224 growth = relax_frag (fragP, stretch);
225
226 /* Long jump on odd halfword boundary? */
227 if (fragP->fr_subtype == 2 && (address & 3) != 0)
228 {
229 fragP->fr_subtype = 3;
230 growth += 2;
231 }
232 }
233
234 return growth;
235 }
236
237 /* Return an initial guess of the length by which a fragment must grow to
238 hold a branch to reach its destination.
239 Also updates fr_type/fr_subtype as necessary.
240
241 Called just before doing relaxation.
242 Any symbol that is now undefined will not become defined.
243 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
244 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
245 Although it may not be explicit in the frag, pretend fr_var starts with a
246 0 value. */
247
248 int
249 md_estimate_size_before_relax (fragP, segment)
250 fragS * fragP;
251 segT segment;
252 {
253 int old_fr_fix = fragP->fr_fix;
254
255 /* The only thing we have to handle here are symbols outside of the
256 current segment. They may be undefined or in a different segment in
257 which case linker scripts may place them anywhere.
258 However, we can't finish the fragment here and emit the reloc as insn
259 alignment requirements may move the insn about. */
260
261 if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
262 {
263 /* The symbol is undefined in this segment.
264 Change the relaxation subtype to the max allowable and leave
265 all further handling to md_convert_frag. */
266 fragP->fr_subtype = 2;
267
268 #if 0 /* Can't use this, but leave in for illustration. */
269 /* Change 16 bit insn to 32 bit insn. */
270 fragP->fr_opcode[0] |= 0x80;
271
272 /* Increase known (fixed) size of fragment. */
273 fragP->fr_fix += 2;
274
275 /* Create a relocation for it. */
276 fix_new (fragP, old_fr_fix, 4,
277 fragP->fr_symbol,
278 fragP->fr_offset, 1 /* pcrel */,
279 /* FIXME: Can't use a real BFD reloc here.
280 gas_cgen_md_apply_fix3 can't handle it. */
281 BFD_RELOC_FR30_26_PCREL);
282
283 /* Mark this fragment as finished. */
284 frag_wane (fragP);
285 #else
286 {
287 const CGEN_INSN * insn;
288 int i;
289
290 /* Update the recorded insn.
291 Fortunately we don't have to look very far.
292 FIXME: Change this to record in the instruction the next higher
293 relaxable insn to use. */
294 for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
295 {
296 if ((strcmp (CGEN_INSN_MNEMONIC (insn),
297 CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
298 == 0)
299 && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX))
300 break;
301 }
302 if (i == 4)
303 abort ();
304
305 fragP->fr_cgen.insn = insn;
306 return 2;
307 }
308 #endif
309 }
310
311 return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
312 }
313
314 /* *fragP has been relaxed to its final size, and now needs to have
315 the bytes inside it modified to conform to the new size.
316
317 Called after relaxation is finished.
318 fragP->fr_type == rs_machine_dependent.
319 fragP->fr_subtype is the subtype of what the address relaxed to. */
320
321 void
322 md_convert_frag (abfd, sec, fragP)
323 bfd * abfd;
324 segT sec;
325 fragS * fragP;
326 {
327 #if 0
328 char * opcode;
329 char * displacement;
330 int target_address;
331 int opcode_address;
332 int extension;
333 int addend;
334
335 opcode = fragP->fr_opcode;
336
337 /* Address opcode resides at in file space. */
338 opcode_address = fragP->fr_address + fragP->fr_fix - 2;
339
340 switch (fragP->fr_subtype)
341 {
342 case 1 :
343 extension = 0;
344 displacement = & opcode[1];
345 break;
346 case 2 :
347 opcode[0] |= 0x80;
348 extension = 2;
349 displacement = & opcode[1];
350 break;
351 case 3 :
352 opcode[2] = opcode[0] | 0x80;
353 md_number_to_chars (opcode, PAR_NOP_INSN, 2);
354 opcode_address += 2;
355 extension = 4;
356 displacement = & opcode[3];
357 break;
358 default :
359 abort ();
360 }
361
362 if (S_GET_SEGMENT (fragP->fr_symbol) != sec)
363 {
364 /* symbol must be resolved by linker */
365 if (fragP->fr_offset & 3)
366 as_warn (_("Addend to unresolved symbol not on word boundary."));
367 addend = fragP->fr_offset >> 2;
368 }
369 else
370 {
371 /* Address we want to reach in file space. */
372 target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
373 target_address += fragP->fr_symbol->sy_frag->fr_address;
374 addend = (target_address - (opcode_address & -4)) >> 2;
375 }
376
377 /* Create a relocation for symbols that must be resolved by the linker.
378 Otherwise output the completed insn. */
379
380 if (S_GET_SEGMENT (fragP->fr_symbol) != sec)
381 {
382 assert (fragP->fr_subtype != 1);
383 assert (fragP->fr_cgen.insn != 0);
384 gas_cgen_record_fixup (fragP,
385 /* Offset of branch insn in frag. */
386 fragP->fr_fix + extension - 4,
387 fragP->fr_cgen.insn,
388 4 /*length*/,
389 /* FIXME: quick hack */
390 #if 0
391 CGEN_OPERAND_ENTRY (fragP->fr_cgen.opindex),
392 #else
393 CGEN_OPERAND_ENTRY (FR30_OPERAND_DISP24),
394 #endif
395 fragP->fr_cgen.opinfo,
396 fragP->fr_symbol, fragP->fr_offset);
397 }
398
399 #define SIZE_FROM_RELAX_STATE(n) ((n) == 1 ? 1 : 3)
400
401 md_number_to_chars (displacement, (valueT) addend,
402 SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
403
404 fragP->fr_fix += extension;
405 #endif
406 }
407 \f
408 /* Functions concerning relocs. */
409
410 /* The location from which a PC relative jump should be calculated,
411 given a PC relative reloc. */
412
413 long
414 md_pcrel_from_section (fixP, sec)
415 fixS * fixP;
416 segT sec;
417 {
418 if (fixP->fx_addsy != (symbolS *) NULL
419 && (! S_IS_DEFINED (fixP->fx_addsy)
420 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
421 {
422 /* The symbol is undefined (or is defined but not in this section).
423 Let the linker figure it out. */
424 return 0;
425 }
426
427 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
428 }
429
430 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
431 Returns BFD_RELOC_NONE if no reloc type can be found.
432 *FIXP may be modified if desired. */
433
434 bfd_reloc_code_real_type
435 md_cgen_lookup_reloc (insn, operand, fixP)
436 const CGEN_INSN * insn;
437 const CGEN_OPERAND * operand;
438 fixS * fixP;
439 {
440 switch (CGEN_OPERAND_TYPE (operand))
441 {
442 case FR30_OPERAND_LABEL9: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_9_PCREL;
443 case FR30_OPERAND_LABEL12: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_12_PCREL;
444 case FR30_OPERAND_DISP10: return BFD_RELOC_FR30_10_IN_8;
445 case FR30_OPERAND_DISP9: return BFD_RELOC_FR30_9_IN_8;
446 case FR30_OPERAND_DISP8: return BFD_RELOC_FR30_8_IN_8;
447 case FR30_OPERAND_UDISP6: return BFD_RELOC_FR30_6_IN_4;
448 case FR30_OPERAND_I8: return BFD_RELOC_8;
449 case FR30_OPERAND_I32: return BFD_RELOC_FR30_48;
450 case FR30_OPERAND_I20: return BFD_RELOC_FR30_20;
451 default : /* avoid -Wall warning */
452 break;
453 }
454
455 return BFD_RELOC_NONE;
456 }
457
458
459 /* Return BFD reloc type from opinfo field in a fixS.
460 It's tricky using fx_r_type in fr30_frob_file because the values
461 are BFD_RELOC_UNUSED + operand number. */
462 #define FX_OPINFO_R_TYPE(f) ((f)->tc_fix_data.opinfo)
463
464 /* See whether we need to force a relocation into the output file.
465 This is used to force out switch and PC relative relocations when
466 relaxing. */
467
468 int
469 fr30_force_relocation (fix)
470 fixS * fix;
471 {
472 if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
473 || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
474 return 1;
475
476 return fix->fx_pcrel;
477 }
478 \f
479 /* Write a value out to the object file, using the appropriate endianness. */
480
481 void
482 md_number_to_chars (buf, val, n)
483 char * buf;
484 valueT val;
485 int n;
486 {
487 number_to_chars_bigendian (buf, val, n);
488 }
489
490 /* Turn a string in input_line_pointer into a floating point constant of type
491 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
492 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
493 */
494
495 /* Equal to MAX_PRECISION in atof-ieee.c */
496 #define MAX_LITTLENUMS 6
497
498 char *
499 md_atof (type, litP, sizeP)
500 char type;
501 char * litP;
502 int * sizeP;
503 {
504 int i;
505 int prec;
506 LITTLENUM_TYPE words [MAX_LITTLENUMS];
507 char * t;
508 char * atof_ieee ();
509
510 switch (type)
511 {
512 case 'f':
513 case 'F':
514 case 's':
515 case 'S':
516 prec = 2;
517 break;
518
519 case 'd':
520 case 'D':
521 case 'r':
522 case 'R':
523 prec = 4;
524 break;
525
526 /* FIXME: Some targets allow other format chars for bigger sizes here. */
527
528 default:
529 * sizeP = 0;
530 return _("Bad call to md_atof()");
531 }
532
533 t = atof_ieee (input_line_pointer, type, words);
534 if (t)
535 input_line_pointer = t;
536 * sizeP = prec * sizeof (LITTLENUM_TYPE);
537
538 for (i = 0; i < prec; i++)
539 {
540 md_number_to_chars (litP, (valueT) words[i],
541 sizeof (LITTLENUM_TYPE));
542 litP += sizeof (LITTLENUM_TYPE);
543 }
544
545 return 0;
546 }
547
548 /* Worker function for fr30_is_colon_insn(). */
549 static char
550 restore_colon (advance_i_l_p_by)
551 int advance_i_l_p_by;
552 {
553 char c;
554
555 /* Restore the colon, and advance input_line_pointer to
556 the end of the new symbol. */
557 * input_line_pointer = ':';
558 input_line_pointer += advance_i_l_p_by;
559 c = * input_line_pointer;
560 * input_line_pointer = 0;
561
562 return c;
563 }
564
565 /* Determines if the symbol starting at START and ending in
566 a colon that was at the location pointed to by INPUT_LINE_POINTER
567 (but which has now been replaced bu a NUL) is in fact an
568 LDI:8, LDI:20, LDI:32, CALL:D. JMP:D, RET:D or Bcc:D instruction.
569 If it is, then it restores the colon, advances INPUT_LINE_POINTER
570 to the real end of the instruction/symbol, and returns the character
571 that really terminated the symbol. Otherwise it returns 0. */
572 char
573 fr30_is_colon_insn (start)
574 char * start;
575 {
576 char * i_l_p = input_line_pointer;
577
578 /* Check to see if the symbol parsed so far is 'ldi' */
579 if ( (start[0] != 'l' && start[0] != 'L')
580 || (start[1] != 'd' && start[1] != 'D')
581 || (start[2] != 'i' && start[2] != 'I')
582 || start[3] != 0)
583 {
584 /* Nope - check to see a 'd' follows the colon. */
585 if ( (i_l_p[1] == 'd' || i_l_p[1] == 'D')
586 && (i_l_p[2] == ' ' || i_l_p[2] == '\t' || i_l_p[2] == '\n'))
587 {
588 /* Yup - it might be delay slot instruction. */
589 int i;
590 static char * delay_insns [] =
591 {
592 "call", "jmp", "ret", "bra", "bno",
593 "beq", "bne", "bc", "bnc", "bn",
594 "bp", "bv", "bnv", "blt", "bge",
595 "ble", "bgt", "bls", "bhi"
596 };
597
598 for (i = sizeof (delay_insns) / sizeof (delay_insns[0]); i--;)
599 {
600 char * insn = delay_insns[i];
601 int len = strlen (insn);
602
603 if (start [len] != 0)
604 continue;
605
606 while (len --)
607 if (tolower (start [len]) != insn [len])
608 break;
609
610 if (len == -1)
611 return restore_colon (1);
612 }
613 }
614
615 /* Nope - it is a normal label. */
616 return 0;
617 }
618
619 /* Check to see if the text following the colon is '8' */
620 if (i_l_p[1] == '8' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
621 return restore_colon (2);
622
623 /* Check to see if the text following the colon is '20' */
624 else if (i_l_p[1] == '2' && i_l_p[2] =='0' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
625 return restore_colon (3);
626
627 /* Check to see if the text following the colon is '32' */
628 else if (i_l_p[1] == '3' && i_l_p[2] =='2' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
629 return restore_colon (3);
630
631 return 0;
632 }