source: trunk/binutils/gas/config/tc-fr30.c@ 2562

Last change on this file since 2562 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

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