1 /* tc-ft32.c -- Assemble code for ft32
2 Copyright (C) 2008-2019 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to
18 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
19 Boston, MA 02110-1301, USA. */
21 /* Contributed by Anthony Green <green@spindazzle.org>. */
24 #include "safe-ctype.h"
25 #include "opcode/ft32.h"
27 extern const ft32_opc_info_t ft32_opc_info
[128];
29 /* See md_parse_option() for meanings of these options. */
30 static char norelax
; /* True if -norelax switch seen. */
32 const char comment_chars
[] = "#";
33 const char line_separator_chars
[] = ";";
34 const char line_comment_chars
[] = "#";
36 static int pending_reloc
;
37 static struct hash_control
*opcode_hash_control
;
39 static valueT
md_chars_to_number (char * buf
, int n
);
41 const pseudo_typeS md_pseudo_table
[] =
46 const char FLT_CHARS
[] = "rRsSfFdDxXpP";
47 const char EXP_CHARS
[] = "eE";
49 /* This function is called once, at assembler startup time. It sets
50 up the hash table with all the opcodes in it, and also initializes
51 some aliases for compatibility with other assemblers. */
56 const ft32_opc_info_t
*opcode
;
57 opcode_hash_control
= hash_new ();
59 /* Insert names into hash table. */
60 for (opcode
= ft32_opc_info
; opcode
->name
; opcode
++)
61 hash_insert (opcode_hash_control
, opcode
->name
, (char *) opcode
);
63 bfd_set_arch_mach (stdoutput
, TARGET_ARCH
, 0);
68 /* Parse an expression and then restore the input line pointer. */
71 parse_exp_save_ilp (char *s
, expressionS
*op
)
73 char *save
= input_line_pointer
;
75 input_line_pointer
= s
;
77 s
= input_line_pointer
;
78 input_line_pointer
= save
;
83 parse_condition (char **ptr
)
93 { "gt," , (2 << FT32_FLD_CR_BIT
) | (5 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
94 { "gte," , (2 << FT32_FLD_CR_BIT
) | (4 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
95 { "lt," , (2 << FT32_FLD_CR_BIT
) | (4 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
96 { "lte," , (2 << FT32_FLD_CR_BIT
) | (5 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
97 { "a," , (2 << FT32_FLD_CR_BIT
) | (6 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
98 { "ae," , (2 << FT32_FLD_CR_BIT
) | (1 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
99 { "be," , (2 << FT32_FLD_CR_BIT
) | (6 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
100 { "b," , (2 << FT32_FLD_CR_BIT
) | (1 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
101 { "nz," , (2 << FT32_FLD_CR_BIT
) | (0 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
102 { "z," , (2 << FT32_FLD_CR_BIT
) | (0 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
103 { "nc," , (2 << FT32_FLD_CR_BIT
) | (1 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
104 { "c," , (2 << FT32_FLD_CR_BIT
) | (1 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
105 { "no," , (2 << FT32_FLD_CR_BIT
) | (2 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
106 { "o," , (2 << FT32_FLD_CR_BIT
) | (2 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
107 { "ns," , (2 << FT32_FLD_CR_BIT
) | (3 << FT32_FLD_CB_BIT
) | (0 << FT32_FLD_CV_BIT
)},
108 { "s," , (2 << FT32_FLD_CR_BIT
) | (3 << FT32_FLD_CB_BIT
) | (1 << FT32_FLD_CV_BIT
)},
112 for (pc
= ccs
; pc
->name
; pc
++)
114 if (memcmp(pc
->name
, s
, strlen(pc
->name
)) == 0)
116 *ptr
+= strlen(pc
->name
) - 1;
124 parse_decimal (char **ptr
)
129 while (('0' <= *s
) && (*s
<= '9'))
139 parse_register_operand (char **ptr
)
146 as_bad (_("expecting register"));
147 ignore_rest_of_line ();
150 if ((s
[1] == 's') && (s
[2] == 'p'))
154 else if ((s
[1] == 'c') && (s
[2] == 'c'))
158 else if ((s
[1] == 'f') && (s
[2] == 'p'))
162 else if (s
[1] == 'r')
165 if ((reg
< 0) || (reg
> 9))
167 as_bad (_("illegal register number"));
168 ignore_rest_of_line ();
171 if ((reg
== 1) || (reg
== 2) || (reg
== 3))
174 if ((r2
>= 0) && (r2
<= 9))
176 reg
= (reg
* 10) + r2
;
183 as_bad (_("illegal register number"));
184 ignore_rest_of_line ();
193 /* This is the guts of the machine-dependent assembler. STR points to
194 a machine dependent instruction. This function is supposed to emit
195 the frags/bytes it assembles to. */
198 md_assemble (char *str
)
202 ft32_opc_info_t
*opcode
;
210 bfd_boolean fixed
= FALSE
;
214 /* Drop leading whitespace. */
218 /* Find the op code end. */
222 && !is_end_of_line
[*op_end
& 0xff]
232 as_bad (_("can't find opcode "));
234 opcode
= (ft32_opc_info_t
*) hash_find (opcode_hash_control
, op_start
);
239 as_bad (_("unknown opcode %s"), op_start
);
264 as_bad (_("unknown width specifier '.%c'"), op_end
[1]);
271 dw
= 2; /* default is ".l" */
273 b
|= dw
<< FT32_FLD_DW_BIT
;
276 while (ISSPACE (*op_end
))
279 output
= frag_more (4);
289 case FT32_FLD_CBCRCV
:
290 b
|= parse_condition( &op_end
);
293 b
|= parse_decimal (&op_end
) << FT32_FLD_CB_BIT
;
296 b
|= parse_register_operand (&op_end
) << FT32_FLD_R_D_BIT
;
299 b
|= (parse_register_operand (&op_end
) - 28) << FT32_FLD_CR_BIT
;
302 b
|= parse_decimal (&op_end
) << FT32_FLD_CV_BIT
;
305 b
|= parse_register_operand (&op_end
) << FT32_FLD_R_1_BIT
;
310 b
|= parse_register_operand (&op_end
) << FT32_FLD_RIMM_BIT
;
314 b
|= 0x400 << FT32_FLD_RIMM_BIT
;
315 op_end
= parse_exp_save_ilp (op_end
, &arg
);
317 fix_new_exp (frag_now
,
318 (output
- frag_now
->fr_literal
),
326 b
|= parse_register_operand (&op_end
) << FT32_FLD_R_2_BIT
;
329 op_end
= parse_exp_save_ilp (op_end
, &arg
);
331 fix_new_exp (frag_now
,
332 (output
- frag_now
->fr_literal
),
339 op_end
= parse_exp_save_ilp (op_end
, &arg
);
341 fix_new_exp (frag_now
,
342 (output
- frag_now
->fr_literal
),
349 op_end
= parse_exp_save_ilp (op_end
, &arg
);
351 fix_new_exp (frag_now
,
352 (output
- frag_now
->fr_literal
),
359 op_end
= parse_exp_save_ilp (op_end
, &arg
);
361 fix_new_exp (frag_now
,
362 (output
- frag_now
->fr_literal
),
369 op_end
= parse_exp_save_ilp (op_end
, &arg
);
370 if (arg
.X_add_number
& 0x80)
371 arg
.X_add_number
^= 0x7f00;
373 fix_new_exp (frag_now
,
374 (output
- frag_now
->fr_literal
),
380 case FT32_FLD_R_D_POST
:
381 b
|= parse_register_operand (&op_end
) << FT32_FLD_R_D_BIT
;
383 case FT32_FLD_R_1_POST
:
384 b
|= parse_register_operand (&op_end
) << FT32_FLD_R_1_BIT
;
387 as_bad (_("internal error in argument parsing"));
395 while (ISSPACE (*op_end
))
400 as_bad (_("expected comma separator"));
401 ignore_rest_of_line ();
405 while (ISSPACE (*op_end
))
412 as_warn (_("extra stuff on line ignored"));
414 can_sc
= ft32_shortcode (b
, &sc
);
416 if (!fixed
&& can_sc
)
418 arg
.X_op
= O_constant
;
419 arg
.X_add_number
= 0;
420 arg
.X_add_symbol
= NULL
;
421 arg
.X_op_symbol
= NULL
;
422 fix_new_exp (frag_now
,
423 (output
- frag_now
->fr_literal
),
427 BFD_RELOC_FT32_RELAX
);
430 output
[idx
++] = 0xff & (b
>> 0);
431 output
[idx
++] = 0xff & (b
>> 8);
432 output
[idx
++] = 0xff & (b
>> 16);
433 output
[idx
++] = 0xff & (b
>> 24);
435 dwarf2_emit_insn (4);
437 while (ISSPACE (*op_end
))
441 as_warn ("extra stuff on line ignored");
444 as_bad ("Something forgot to clean up\n");
447 /* Turn a string in input_line_pointer into a floating point constant
448 of type type, and store the appropriate bytes in *LITP. The number
449 of LITTLENUMS emitted is stored in *SIZEP . An error message is
450 returned, or NULL on OK. */
453 md_atof (int type
, char *litP
, int *sizeP
)
456 LITTLENUM_TYPE words
[4];
472 return _("bad call to md_atof");
475 t
= atof_ieee (input_line_pointer
, type
, words
);
477 input_line_pointer
= t
;
481 for (i
= prec
- 1; i
>= 0; i
--)
483 md_number_to_chars (litP
, (valueT
) words
[i
], 2);
490 const char *md_shortopts
= "";
492 struct option md_longopts
[] =
494 #define OPTION_NORELAX (OPTION_MD_BASE)
495 {"norelax", no_argument
, NULL
, OPTION_NORELAX
},
496 {"no-relax", no_argument
, NULL
, OPTION_NORELAX
},
497 {NULL
, no_argument
, NULL
, 0}
499 size_t md_longopts_size
= sizeof (md_longopts
);
501 /* We have no target specific options yet, so these next
502 two functions are empty. */
504 md_parse_option (int c ATTRIBUTE_UNUSED
, const char *arg ATTRIBUTE_UNUSED
)
520 md_show_usage (FILE *stream ATTRIBUTE_UNUSED
)
522 fprintf (stream
, _("FT32 options:\n"));
523 fprintf (stream
, _("\n\
524 -no-relax don't relax relocations\n\
528 /* Convert from target byte order to host byte order. */
531 md_chars_to_number (char * buf
, int n
)
534 unsigned char * where
= (unsigned char *) buf
;
539 result
|= (where
[n
] & 255);
545 /* Apply a fixup to the object file. */
548 md_apply_fix (fixS
*fixP ATTRIBUTE_UNUSED
,
549 valueT
* valP ATTRIBUTE_UNUSED
, segT seg ATTRIBUTE_UNUSED
)
551 char *buf
= fixP
->fx_where
+ fixP
->fx_frag
->fr_literal
;
555 if (linkrelax
&& fixP
->fx_subsy
)
557 /* For a subtraction relocation expression, generate one
558 of the DIFF relocs, with the value being the difference.
559 Note that a sym1 - sym2 expression is adjusted into a
560 section_start_sym + sym4_offset_from_section_start - sym1
561 expression. fixP->fx_addsy holds the section start symbol,
562 fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
563 holds sym1. Calculate the current difference and write value,
564 but leave fx_offset as is - during relaxation,
565 fx_offset - value gives sym1's value. */
567 switch (fixP
->fx_r_type
)
570 fixP
->fx_r_type
= BFD_RELOC_FT32_DIFF32
;
573 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
574 _("expression too complex"));
578 val
= S_GET_VALUE (fixP
->fx_addsy
) +
579 fixP
->fx_offset
- S_GET_VALUE (fixP
->fx_subsy
);
582 fixP
->fx_subsy
= NULL
;
585 /* We don't actually support subtracting a symbol. */
586 if (fixP
->fx_subsy
!= (symbolS
*) NULL
)
587 as_bad_where (fixP
->fx_file
, fixP
->fx_line
, _("expression too complex"));
589 switch (fixP
->fx_r_type
)
591 case BFD_RELOC_FT32_DIFF32
:
608 case BFD_RELOC_FT32_10
:
611 newval
= md_chars_to_number (buf
, 2);
612 newval
|= (val
& ((1 << 10) - 1)) << FT32_FLD_RIMM_BIT
;
613 md_number_to_chars (buf
, newval
, 2);
616 case BFD_RELOC_FT32_20
:
619 newval
= md_chars_to_number (buf
, 3);
620 newval
|= val
& ((1 << 20) - 1);
621 md_number_to_chars (buf
, newval
, 3);
624 case BFD_RELOC_FT32_15
:
627 newval
= md_chars_to_number (buf
, 2);
628 newval
|= val
& ((1 << 15) - 1);
629 md_number_to_chars (buf
, newval
, 2);
632 case BFD_RELOC_FT32_17
:
635 newval
= md_chars_to_number (buf
, 3);
636 newval
|= val
& ((1 << 17) - 1);
637 md_number_to_chars (buf
, newval
, 3);
640 case BFD_RELOC_FT32_18
:
643 newval
= md_chars_to_number (buf
, 4);
644 newval
|= (val
>> 2) & ((1 << 18) - 1);
645 md_number_to_chars (buf
, newval
, 4);
648 case BFD_RELOC_FT32_RELAX
:
655 if (fixP
->fx_addsy
== NULL
&& fixP
->fx_pcrel
== 0)
660 md_number_to_chars (char *ptr
, valueT use
, int nbytes
)
662 number_to_chars_littleendian (ptr
, use
, nbytes
);
665 /* Generate a machine-dependent relocation. */
668 tc_gen_reloc (asection
*section ATTRIBUTE_UNUSED
, fixS
*fixP
)
671 bfd_reloc_code_real_type code
;
673 switch (fixP
->fx_r_type
)
678 case BFD_RELOC_FT32_10
:
679 case BFD_RELOC_FT32_20
:
680 case BFD_RELOC_FT32_15
:
681 case BFD_RELOC_FT32_17
:
682 case BFD_RELOC_FT32_18
:
683 case BFD_RELOC_FT32_RELAX
:
684 case BFD_RELOC_FT32_DIFF32
:
685 code
= fixP
->fx_r_type
;
688 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
689 _("Semantics error. This type of operand can not be "
690 "relocated, it must be an assembly-time constant"));
694 relP
= XNEW (arelent
);
695 gas_assert (relP
!= 0);
696 relP
->sym_ptr_ptr
= XNEW (asymbol
*);
697 *relP
->sym_ptr_ptr
= symbol_get_bfdsym (fixP
->fx_addsy
);
698 relP
->address
= fixP
->fx_frag
->fr_address
+ fixP
->fx_where
;
700 relP
->addend
= fixP
->fx_offset
;
702 relP
->howto
= bfd_reloc_type_lookup (stdoutput
, code
);
707 name
= S_GET_NAME (fixP
->fx_addsy
);
709 name
= _("<unknown>");
710 as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
711 name
, bfd_get_reloc_code_name (code
));
717 /* TC_FORCE_RELOCATION hook */
720 relaxable_section (asection
*sec
)
722 return ((sec
->flags
& SEC_DEBUGGING
) == 0
723 && (sec
->flags
& SEC_CODE
) != 0
724 && (sec
->flags
& SEC_ALLOC
) != 0);
727 /* Does whatever the xtensa port does. */
730 ft32_validate_fix_sub (fixS
*fix
)
732 segT add_symbol_segment
, sub_symbol_segment
;
734 /* The difference of two symbols should be resolved by the assembler when
735 linkrelax is not set. If the linker may relax the section containing
736 the symbols, then an Xtensa DIFF relocation must be generated so that
737 the linker knows to adjust the difference value. */
738 if (!linkrelax
|| fix
->fx_addsy
== NULL
)
741 /* Make sure both symbols are in the same segment, and that segment is
742 "normal" and relaxable. If the segment is not "normal", then the
743 fix is not valid. If the segment is not "relaxable", then the fix
744 should have been handled earlier. */
745 add_symbol_segment
= S_GET_SEGMENT (fix
->fx_addsy
);
746 if (! SEG_NORMAL (add_symbol_segment
) ||
747 ! relaxable_section (add_symbol_segment
))
750 sub_symbol_segment
= S_GET_SEGMENT (fix
->fx_subsy
);
751 return (sub_symbol_segment
== add_symbol_segment
);
754 /* TC_FORCE_RELOCATION hook */
756 /* If linkrelax is turned on, and the symbol to relocate
757 against is in a relaxable segment, don't compute the value -
758 generate a relocation instead. */
761 ft32_force_relocation (fixS
*fix
)
763 if (linkrelax
&& fix
->fx_addsy
764 && relaxable_section (S_GET_SEGMENT (fix
->fx_addsy
)))
769 return generic_force_reloc (fix
);
773 ft32_allow_local_subtract (expressionS
* left
,
777 /* If we are not in relaxation mode, subtraction is OK. */
781 /* If the symbols are not in a code section then they are OK. */
782 if ((section
->flags
& SEC_CODE
) == 0)
785 if (left
->X_add_symbol
== right
->X_add_symbol
)
788 /* We have to assume that there may be instructions between the
789 two symbols and that relaxation may increase the distance between