]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/config/tc-tic54x.c
Regenerate cgen files
[thirdparty/binutils-gdb.git] / gas / config / tc-tic54x.c
CommitLineData
39bec121 1/* tc-tic54x.c -- Assembly code for the Texas Instruments TMS320C54X
f1e7a2c9 2 Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
39bec121
TW
3 Contributed by Timothy Wall (twall@cygnus.com)
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 the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21
d0313fb7 22/* Texas Instruments TMS320C54X machine specific gas.
39bec121
TW
23 Written by Timothy Wall (twall@alum.mit.edu).
24
25 Valuable things to do:
26 Pipeline conflict warnings
27 We encode/decode "ld #_label, dp" differently in relocatable files
28 This means we're not compatible with TI output containing those
29 expressions. We store the upper nine bits; TI stores the lower nine
30 bits. How they recover the original upper nine bits is beyond me.
31
32 Tests to add to expect testsuite:
33 '=' and '==' with .if, .elseif, and .break
34
35 Incompatibilities (mostly trivial):
36 We don't allow '''
37 We fill text section with zeroes instead of "nop"s
38 We don't convert '' or "" to a single instance
39 We don't convert '' to '\0'
40 We don't allow strings with .byte/.half/.short/.long
41 Probably details of the subsym stuff are different
6e917903
TW
42 TI sets labels to be data type 4 (T_INT); GAS uses T_NULL.
43
44 COFF1 limits section names to 8 characters.
f1e7a2c9 45 Some of the default behavior changed from COFF1 to COFF2. */
39bec121
TW
46
47#include <stdlib.h>
48#include <limits.h>
49#include <errno.h>
50#include "as.h"
3882b010 51#include "safe-ctype.h"
39bec121
TW
52#include "sb.h"
53#include "macro.h"
54#include "subsegs.h"
55#include "struc-symbol.h"
56#include "opcode/tic54x.h"
57#include "obj-coff.h"
58#include <math.h>
59
39bec121 60
f1e7a2c9
NC
61static struct stag
62{
63 symbolS *sym; /* Symbol for this stag; value is offset. */
64 const char *name; /* Shortcut to symbol name. */
65 bfd_vma size; /* Size of struct/union. */
66 int current_bitfield_offset; /* Temporary for tracking fields. */
67 int is_union;
68 struct stag_field /* List of fields. */
69 {
70 const char *name;
71 bfd_vma offset; /* Of start of this field. */
72 int bitfield_offset; /* Of start of this field. */
73 struct stag *stag; /* If field is struct/union. */
74 struct stag_field *next;
75 } *field;
76 /* For nesting; used only in stag construction. */
77 struct stag *inner; /* Enclosed .struct. */
78 struct stag *outer; /* Enclosing .struct. */
79} *current_stag = NULL;
39bec121 80
f1e7a2c9 81#define MAX_LINE 256 /* Lines longer than this are truncated by TI's asm. */
9a736b6b 82
f1e7a2c9
NC
83typedef struct _tic54x_insn
84{
85 const template *tm; /* Opcode template. */
39bec121 86
f1e7a2c9
NC
87 char mnemonic[MAX_LINE]; /* Opcode name/mnemonic. */
88 char parmnemonic[MAX_LINE]; /* 2nd mnemonic of parallel insn. */
39bec121 89
f1e7a2c9
NC
90 int opcount;
91 struct opstruct
92 {
93 char buf[MAX_LINE];
94 enum optype type;
95 expressionS exp;
96 } operands[MAX_OPERANDS];
39bec121 97
f1e7a2c9
NC
98 int paropcount;
99 struct opstruct paroperands[MAX_OPERANDS];
100
101 int is_lkaddr;
102 int lkoperand;
103 int words; /* Size of insn in 16-bit words. */
104 int using_default_dst; /* Do we need to explicitly set an
105 omitted OP_DST operand? */
106 struct
107 {
108 unsigned short word; /* Final encoded opcode data. */
109 int unresolved;
110 int r_nchars; /* Relocation size. */
111 bfd_reloc_code_real_type r_type; /* Relocation type. */
112 expressionS addr_expr; /* Storage for unresolved expressions. */
113 } opcode[3];
114} tic54x_insn;
d0313fb7
NC
115
116enum cpu_version
117{
39bec121
TW
118 VNONE = 0, V541 = 1, V542 = 2, V543 = 3, V545 = 5, V548 = 8, V549 = 9,
119 V545LP = 15, V546LP = 16
120};
121
d0313fb7
NC
122enum address_mode
123{
9a736b6b
NC
124 c_mode, /* 16-bit addresses. */
125 far_mode /* >16-bit addresses. */
39bec121
TW
126};
127
f1e7a2c9
NC
128static segT stag_saved_seg;
129static subsegT stag_saved_subseg;
130
131const char comment_chars[] = ";";
132const char line_comment_chars[] = ";*#"; /* At column zero only. */
133const char line_separator_chars[] = ""; /* Not permitted. */
134
135int emitting_long = 0;
136
137/* Characters which indicate that this is a floating point constant. */
138const char FLT_CHARS[] = "fF";
139
140/* Characters that can be used to separate mantissa from exp in FP
141 nums. */
142const char EXP_CHARS[] = "eE";
143
144const char *md_shortopts = "";
145
39bec121 146#define OPTION_ADDRESS_MODE (OPTION_MD_BASE)
1aea3bb8
NC
147#define OPTION_CPU_VERSION (OPTION_ADDRESS_MODE + 1)
148#define OPTION_COFF_VERSION (OPTION_CPU_VERSION + 1)
149#define OPTION_STDERR_TO_FILE (OPTION_COFF_VERSION + 1)
39bec121 150
1aea3bb8 151struct option md_longopts[] =
39bec121 152{
f1e7a2c9
NC
153 { "mfar-mode", no_argument, NULL, OPTION_ADDRESS_MODE },
154 { "mf", no_argument, NULL, OPTION_ADDRESS_MODE },
155 { "mcpu", required_argument, NULL, OPTION_CPU_VERSION },
39bec121 156 { "merrors-to-file", required_argument, NULL, OPTION_STDERR_TO_FILE },
f1e7a2c9
NC
157 { "me", required_argument, NULL, OPTION_STDERR_TO_FILE },
158 { NULL, no_argument, NULL, 0},
39bec121
TW
159};
160
161size_t md_longopts_size = sizeof (md_longopts);
162
d0313fb7 163static int assembly_begun = 0;
39bec121
TW
164/* Addressing mode is not entirely implemented; the latest rev of the Other
165 assembler doesn't seem to make any distinction whatsoever; all relocations
166 are stored as extended relocatiosn. Older versions used REL16 vs RELEXT16,
167 but now it seems all relocations are RELEXT16. We use all RELEXT16.
168
169 The cpu version is kind of a waste of time as well. There is one
170 instruction (RND) for LP devices only, and several for devices with
d0313fb7 171 extended addressing only. We include it for compatibility. */
39bec121 172static enum address_mode amode = c_mode;
d0313fb7 173static enum cpu_version cpu = VNONE;
39bec121 174
d0313fb7 175/* Include string substitutions in listing? */
39bec121 176static int listing_sslist = 0;
9a736b6b 177
d0313fb7 178/* Did we do subsym substitutions on the line? */
39bec121 179static int substitution_line = 0;
9a736b6b 180
d0313fb7 181/* Last label seen. */
39bec121 182static symbolS *last_label_seen = NULL;
9a736b6b 183
d0313fb7 184/* This ensures that all new labels are unique. */
39bec121
TW
185static int local_label_id;
186
1dab94dd 187static struct hash_control *subsym_recurse_hash; /* Prevent infinite recurse. */
9a736b6b 188static struct hash_control *math_hash; /* Built-in math functions. */
d0313fb7
NC
189/* Allow maximum levels of macro nesting; level 0 is the main substitution
190 symbol table. The other assembler only does 32 levels, so there! */
39bec121 191static struct hash_control *subsym_hash[100];
9a736b6b 192
1aea3bb8 193/* Keep track of local labels so we can substitute them before GAS sees them
39bec121
TW
194 since macros use their own 'namespace' for local labels, use a separate hash
195
196 We do our own local label handling 'cuz it's subtly different from the
197 stock GAS handling.
198
199 We use our own macro nesting counter, since GAS overloads it when expanding
d0313fb7 200 other things (like conditionals and repeat loops). */
39bec121
TW
201static int macro_level = 0;
202static struct hash_control *local_label_hash[100];
d0313fb7 203/* Keep track of struct/union tags. */
39bec121
TW
204static struct hash_control *stag_hash;
205static struct hash_control *op_hash;
206static struct hash_control *parop_hash;
207static struct hash_control *reg_hash;
208static struct hash_control *mmreg_hash;
209static struct hash_control *cc_hash;
210static struct hash_control *cc2_hash;
211static struct hash_control *cc3_hash;
212static struct hash_control *sbit_hash;
213static struct hash_control *misc_symbol_hash;
214
f1e7a2c9
NC
215/* Only word (et al.), align, or conditionals are allowed within
216 .struct/.union. */
217#define ILLEGAL_WITHIN_STRUCT() \
218 do \
219 if (current_stag != NULL) \
220 { \
221 as_bad (_("pseudo-op illegal within .struct/.union")); \
222 return; \
223 } \
224 while (0)
39bec121 225
f1e7a2c9
NC
226static void tic54x_emit_char PARAMS ((char));
227static fragS * frag_prev PARAMS ((fragS *, segT));
228static fragS * bit_offset_frag PARAMS ((fragS *, segT));
229static int frag_bit_offset PARAMS ((fragS *, segT));
230static char * parse_expression PARAMS ((char *, expressionS *));
231static void tic54x_asg PARAMS ((int));
232static void tic54x_eval PARAMS ((int));
233static void tic54x_bss PARAMS ((int));
234static void stag_add_field_symbols PARAMS ((struct stag *, const char *, bfd_vma, symbolS *, const char *));
235static void stag_add_field PARAMS ((struct stag *, const char *, bfd_vma, struct stag *));
236static void tic54x_struct PARAMS ((int));
237static void tic54x_endstruct PARAMS ((int));
238static void tic54x_tag PARAMS ((int));
239static void tic54x_struct_field PARAMS ((int));
240static void tic54x_cons PARAMS ((int));
241static void tic54x_remove_local_label PARAMS ((const char *, PTR));
242static void tic54x_clear_local_labels PARAMS ((int));
243static void tic54x_sect PARAMS ((int));
244static void tic54x_space PARAMS ((int));
245static void tic54x_usect PARAMS ((int));
246static enum cpu_version lookup_version PARAMS ((const char *));
247static void set_cpu PARAMS ((enum cpu_version));
248static void tic54x_version PARAMS ((int));
249static void tic54x_float_cons PARAMS ((int));
250static void tic54x_stringer PARAMS ((int));
251static void tic54x_p2align PARAMS ((int));
252static void tic54x_align_words PARAMS ((int));
253static void tic54x_field PARAMS ((int));
254static int tic54x_initialized_section PARAMS ((segT));
255static void tic54x_clink PARAMS ((int));
256static void tic54x_set_default_include PARAMS ((int));
257static void tic54x_include PARAMS ((int));
258static void tic54x_message PARAMS ((int));
259static void tic54x_label PARAMS ((int));
260static void tic54x_mmregs PARAMS ((int));
261static void tic54x_loop PARAMS ((int));
262static void tic54x_endloop PARAMS ((int));
263static void tic54x_break PARAMS ((int));
264static void set_address_mode PARAMS ((int));
265static void tic54x_address_mode PARAMS ((int));
266static void tic54x_sblock PARAMS ((int));
267static void tic54x_set PARAMS ((int));
268static void tic54x_fclist PARAMS ((int));
269static void tic54x_sslist PARAMS ((int));
270static void tic54x_var PARAMS ((int));
271static void tic54x_mlib PARAMS ((int));
272static int subsym_symlen PARAMS ((char *, char *));
273static int subsym_symcmp PARAMS ((char *, char *));
274static int subsym_firstch PARAMS ((char *, char *));
275static int subsym_lastch PARAMS ((char *, char *));
276static int subsym_isdefed PARAMS ((char *, char *));
277static int subsym_ismember PARAMS ((char *, char *));
278static int subsym_iscons PARAMS ((char *, char *));
279static int subsym_isname PARAMS ((char *, char *));
280static int subsym_isreg PARAMS ((char *, char *));
281static int subsym_structsz PARAMS ((char *, char *));
282static int subsym_structacc PARAMS ((char *, char *));
283static float math_ceil PARAMS ((float, float));
284static float math_cvi PARAMS ((float, float));
285static float math_floor PARAMS ((float, float));
286static float math_fmod PARAMS ((float, float));
287static float math_int PARAMS ((float, float));
288static float math_round PARAMS ((float, float));
289static float math_sgn PARAMS ((float, float));
290static float math_trunc PARAMS ((float, float));
291static float math_acos PARAMS ((float, float));
292static float math_asin PARAMS ((float, float));
293static float math_atan PARAMS ((float, float));
294static float math_atan2 PARAMS ((float, float));
295static float math_cosh PARAMS ((float, float));
296static float math_cos PARAMS ((float, float));
297static float math_cvf PARAMS ((float, float));
298static float math_exp PARAMS ((float, float));
299static float math_fabs PARAMS ((float, float));
300static float math_ldexp PARAMS ((float, float));
301static float math_log10 PARAMS ((float, float));
302static float math_log PARAMS ((float, float));
303static float math_max PARAMS ((float, float));
304static float math_min PARAMS ((float, float));
305static float math_pow PARAMS ((float, float));
306static float math_sin PARAMS ((float, float));
307static float math_sinh PARAMS ((float, float));
308static float math_sqrt PARAMS ((float, float));
309static float math_tan PARAMS ((float, float));
310static float math_tanh PARAMS ((float, float));
311static int is_accumulator PARAMS ((struct opstruct *));
312static int get_operands PARAMS ((struct opstruct operands[], char *));
313static int is_immediate PARAMS ((struct opstruct *));
314static int is_absolute PARAMS ((struct opstruct *));
315static int is_indirect PARAMS ((struct opstruct *));
316static int is_dual PARAMS ((struct opstruct *));
317static int is_mmreg PARAMS ((struct opstruct *));
318static int is_type PARAMS ((struct opstruct *, enum optype));
319static int operands_match PARAMS ((tic54x_insn *, struct opstruct *, int, const enum optype *, int, int));
320static int encode_dmad PARAMS ((tic54x_insn *, struct opstruct *, int));
321static int encode_address PARAMS ((tic54x_insn *, struct opstruct *));
322static int encode_indirect PARAMS ((tic54x_insn *, struct opstruct *));
323static int encode_integer PARAMS ((tic54x_insn *, struct opstruct *, int, int, int, unsigned short));
324static int encode_condition PARAMS ((tic54x_insn *, struct opstruct *));
325static int encode_cc3 PARAMS ((tic54x_insn *, struct opstruct *));
326static int encode_arx PARAMS ((tic54x_insn *, struct opstruct *));
327static int encode_cc2 PARAMS ((tic54x_insn *, struct opstruct *));
328static int encode_operand PARAMS ((tic54x_insn *, enum optype, struct opstruct *));
329static void emit_insn PARAMS ((tic54x_insn *));
330static int build_insn PARAMS ((tic54x_insn *));
331static int optimize_insn PARAMS ((tic54x_insn *));
332static int tic54x_parse_insn PARAMS ((tic54x_insn *, char *));
333static int next_line_shows_parallel PARAMS ((char *));
334static int tic54x_parse_parallel_insn_firstline PARAMS ((tic54x_insn *, char *));
335static int tic54x_parse_parallel_insn_lastline PARAMS ((tic54x_insn *, char *));
336static char * subsym_get_arg PARAMS ((char *, char *, char **, int));
337static void subsym_create_or_replace PARAMS ((char *, char *));
338static char * subsym_lookup PARAMS ((char *, int));
339static char * subsym_substitute PARAMS ((char *, int));
39bec121 340
f1e7a2c9
NC
341
342void
343md_show_usage (stream)
344 FILE *stream;
345{
346 fprintf (stream, _("C54x-specific command line options:\n"));
347 fprintf (stream, _("-mfar-mode | -mf Use extended addressing\n"));
348 fprintf (stream, _("-mcpu=<CPU version> Specify the CPU version\n"));
f1e7a2c9
NC
349 fprintf (stream, _("-merrors-to-file <filename>\n"));
350 fprintf (stream, _("-me <filename> Redirect errors to a file\n"));
351}
39bec121 352
d0313fb7 353/* Output a single character (upper octect is zero). */
9a736b6b 354
d0313fb7 355static void
f1e7a2c9
NC
356tic54x_emit_char (c)
357 char c;
39bec121
TW
358{
359 expressionS exp;
360
361 exp.X_op = O_constant;
362 exp.X_add_number = c;
363 emit_expr (&exp, 2);
364}
365
d0313fb7 366/* Walk backwards in the frag chain. */
9a736b6b 367
39bec121 368static fragS *
f1e7a2c9
NC
369frag_prev (frag, seg)
370 fragS *frag;
371 segT seg;
39bec121
TW
372{
373 segment_info_type *seginfo = seg_info (seg);
374 fragS *fragp;
375
d0313fb7 376 for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
39bec121
TW
377 if (fragp->fr_next == frag)
378 return fragp;
1aea3bb8 379
39bec121
TW
380 return NULL;
381}
382
383static fragS *
f1e7a2c9
NC
384bit_offset_frag (frag, seg)
385 fragS *frag;
386 segT seg;
39bec121
TW
387{
388 while (frag != NULL)
389 {
d0313fb7
NC
390 if (frag->fr_fix == 0
391 && frag->fr_opcode == NULL
392 && frag->tc_frag_data == 0)
393 frag = frag_prev (frag, seg);
39bec121 394 else
d0313fb7 395 return frag;
39bec121
TW
396 }
397 return NULL;
398}
399
d0313fb7
NC
400/* Return the number of bits allocated in the most recent word, or zero if
401 none. .field/.space/.bes may leave words partially allocated. */
9a736b6b 402
39bec121 403static int
f1e7a2c9
NC
404frag_bit_offset (frag, seg)
405 fragS *frag;
406 segT seg;
39bec121
TW
407{
408 frag = bit_offset_frag (frag, seg);
1aea3bb8 409
39bec121 410 if (frag)
d0313fb7
NC
411 return frag->fr_opcode != NULL ? -1 : frag->tc_frag_data;
412
39bec121
TW
413 return 0;
414}
415
d0313fb7
NC
416/* Read an expression from a C string; returns a pointer past the end of the
417 expression. */
9a736b6b 418
39bec121 419static char *
f1e7a2c9
NC
420parse_expression (str, exp)
421 char *str;
422 expressionS * exp;
39bec121
TW
423{
424 char *s;
425 char *tmp;
426
427 tmp = input_line_pointer; /* Save line pointer. */
428 input_line_pointer = str;
429 expression (exp);
430 s = input_line_pointer;
431 input_line_pointer = tmp; /* Restore line pointer. */
432 return s; /* Return pointer to where parsing stopped. */
433}
434
1aea3bb8
NC
435/* .asg "character-string"|character-string, symbol
436
39bec121
TW
437 .eval is the only pseudo-op allowed to perform arithmetic on substitution
438 symbols. all other use of symbols defined with .asg are currently
d0313fb7 439 unsupported. */
9a736b6b 440
d0313fb7 441static void
f1e7a2c9
NC
442tic54x_asg (x)
443 int x ATTRIBUTE_UNUSED;
39bec121
TW
444{
445 int c;
446 char *name;
447 char *str;
448 char *tmp;
449 int quoted = *input_line_pointer == '"';
450
451 ILLEGAL_WITHIN_STRUCT ();
452
453 if (quoted)
454 {
455 int len;
456 str = demand_copy_C_string (&len);
457 c = *input_line_pointer;
458 }
459 else
460 {
461 str = input_line_pointer;
462 while ((c = *input_line_pointer) != ',')
d0313fb7
NC
463 {
464 if (is_end_of_line[(int) *input_line_pointer])
465 break;
466 ++input_line_pointer;
467 }
39bec121
TW
468 *input_line_pointer = 0;
469 }
470 if (c != ',')
471 {
472 as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'"));
473 ignore_rest_of_line ();
474 return;
475 }
476
477 name = ++input_line_pointer;
478 c = get_symbol_end (); /* Get terminator. */
3882b010 479 if (!ISALPHA (*name))
39bec121
TW
480 {
481 as_bad ("symbols assigned with .asg must begin with a letter");
482 ignore_rest_of_line ();
483 return;
484 }
485
486 tmp = xmalloc (strlen (str) + 1);
487 strcpy (tmp, str);
488 str = tmp;
489 tmp = xmalloc (strlen (name) + 1);
490 strcpy (tmp, name);
491 name = tmp;
492 subsym_create_or_replace (name, str);
493 *input_line_pointer = c;
494 demand_empty_rest_of_line ();
495}
496
1aea3bb8 497/* .eval expression, symbol
39bec121 498 There's something screwy about this. The other assembler sometimes does and
1aea3bb8 499 sometimes doesn't substitute symbols defined with .eval.
39bec121 500 We'll put the symbols into the subsym table as well as the normal symbol
d0313fb7 501 table, since that's what works best. */
9a736b6b 502
d0313fb7 503static void
f1e7a2c9
NC
504tic54x_eval (x)
505 int x ATTRIBUTE_UNUSED;
39bec121
TW
506{
507 char c;
508 int value;
509 char *name;
510 symbolS *symbolP;
511 char valuestr[32], *tmp;
512 int quoted;
513
514 ILLEGAL_WITHIN_STRUCT ();
515
516 SKIP_WHITESPACE ();
517
518 quoted = *input_line_pointer == '"';
519 if (quoted)
520 ++input_line_pointer;
521 value = get_absolute_expression ();
522 if (quoted)
523 {
524 if (*input_line_pointer != '"')
d0313fb7
NC
525 {
526 as_bad (_("Unterminated string after absolute expression"));
527 ignore_rest_of_line ();
528 return;
529 }
39bec121
TW
530 ++input_line_pointer;
531 }
532 if (*input_line_pointer++ != ',')
533 {
534 as_bad (_("Comma and symbol expected for '.eval EXPR, SYMBOL'"));
535 ignore_rest_of_line ();
536 return;
537 }
538 name = input_line_pointer;
539 c = get_symbol_end (); /* Get terminator. */
d0313fb7 540 tmp = xmalloc (strlen (name) + 1);
39bec121
TW
541 name = strcpy (tmp, name);
542 *input_line_pointer = c;
543
3882b010 544 if (!ISALPHA (*name))
39bec121
TW
545 {
546 as_bad (_("symbols assigned with .eval must begin with a letter"));
547 ignore_rest_of_line ();
548 return;
549 }
550 symbolP = symbol_new (name, absolute_section,
551 (valueT) value, &zero_address_frag);
552 SF_SET_LOCAL (symbolP);
553 symbol_table_insert (symbolP);
554
555 /* The "other" assembler sometimes doesn't put .eval's in the subsym table
556 But since there's not written rule as to when, don't even bother trying
d0313fb7 557 to match their behavior. */
39bec121
TW
558 sprintf (valuestr, "%d", value);
559 tmp = xmalloc (strlen (valuestr) + 1);
560 strcpy (tmp, valuestr);
561 subsym_create_or_replace (name, tmp);
562
563 demand_empty_rest_of_line ();
564}
565
1aea3bb8 566/* .bss symbol, size [, [blocking flag] [, alignment flag]
39bec121
TW
567
568 alignment is to a longword boundary; blocking is to 128-word boundary.
569
570 1) if there is a hole in memory, this directive should attempt to fill it
571 (not yet implemented).
572
573 2) if the blocking flag is not set, allocate at the current SPC
574 otherwise, check to see if the current SPC plus the space to be
575 allocated crosses the page boundary (128 words).
576 if there's not enough space, create a hole and align with the next page
1aea3bb8 577 boundary.
d0313fb7 578 (not yet implemented). */
9a736b6b 579
d0313fb7 580static void
f1e7a2c9
NC
581tic54x_bss (x)
582 int x ATTRIBUTE_UNUSED;
39bec121
TW
583{
584 char c;
585 char *name;
586 char *p;
587 int words;
588 segT current_seg;
589 subsegT current_subseg;
590 symbolS *symbolP;
591 int block = 0;
592 int align = 0;
593
594 ILLEGAL_WITHIN_STRUCT ();
595
d0313fb7
NC
596 current_seg = now_seg; /* Save current seg. */
597 current_subseg = now_subseg; /* Save current subseg. */
39bec121
TW
598
599 name = input_line_pointer;
600 c = get_symbol_end (); /* Get terminator. */
601 if (c != ',')
602 {
603 as_bad (".bss size argument missing\n");
604 ignore_rest_of_line ();
605 return;
606 }
607
608 ++input_line_pointer;
609 words = get_absolute_expression ();
610 if (words < 0)
611 {
612 as_bad (".bss size %d < 0!", words);
613 ignore_rest_of_line ();
614 return;
615 }
616
617 if (*input_line_pointer == ',')
618 {
9a736b6b 619 /* The blocking flag may be missing. */
39bec121
TW
620 ++input_line_pointer;
621 if (*input_line_pointer != ',')
d0313fb7 622 block = get_absolute_expression ();
39bec121 623 else
d0313fb7 624 block = 0;
39bec121
TW
625
626 if (*input_line_pointer == ',')
d0313fb7
NC
627 {
628 ++input_line_pointer;
629 align = get_absolute_expression ();
630 }
39bec121 631 else
d0313fb7 632 align = 0;
39bec121
TW
633 }
634 else
635 block = align = 0;
636
637 subseg_set (bss_section, 0);
638 symbolP = symbol_find_or_make (name);
639
640 if (S_GET_SEGMENT (symbolP) == bss_section)
641 symbolP->sy_frag->fr_symbol = (symbolS *) NULL;
642
643 symbol_set_frag (symbolP, frag_now);
644 p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
6e917903 645 (offsetT) (words * OCTETS_PER_BYTE), (char *) 0);
9a736b6b 646 *p = 0; /* Fill char. */
39bec121
TW
647
648 S_SET_SEGMENT (symbolP, bss_section);
649
650 /* The symbol may already have been created with a preceding
651 ".globl" directive -- be careful not to step on storage class
652 in that case. Otherwise, set it to static. */
653 if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
654 S_SET_STORAGE_CLASS (symbolP, C_STAT);
655
656 if (align)
657 {
658 /* s_align eats end of line; restore it */
659 s_align_bytes (4);
660 --input_line_pointer;
661 }
662
663 if (block)
1aea3bb8 664 bss_section->flags |= SEC_BLOCK;
39bec121 665
9a736b6b 666 subseg_set (current_seg, current_subseg); /* Restore current seg. */
39bec121
TW
667 demand_empty_rest_of_line ();
668}
669
670static void
f1e7a2c9
NC
671stag_add_field_symbols (stag, path, base_offset, rootsym, root_stag_name)
672 struct stag *stag;
673 const char *path;
674 bfd_vma base_offset;
675 symbolS *rootsym;
676 const char *root_stag_name;
39bec121
TW
677{
678 char prefix[strlen (path) + 2];
679 struct stag_field *field = stag->field;
1aea3bb8
NC
680
681 /* Construct a symbol for every field contained within this structure
d0313fb7 682 including fields within structure fields. */
39bec121
TW
683 strcpy (prefix, path);
684 if (*path)
685 strcat (prefix, ".");
686
687 while (field != NULL)
688 {
689 int len = strlen (prefix) + strlen (field->name) + 2;
690 char *name = xmalloc (len);
691 strcpy (name, prefix);
692 strcat (name, field->name);
693
694 if (rootsym == NULL)
9a736b6b
NC
695 {
696 symbolS *sym;
697 sym = symbol_new (name, absolute_section,
698 (field->stag ? field->offset :
699 (valueT) (base_offset + field->offset)),
700 &zero_address_frag);
701 SF_SET_LOCAL (sym);
702 symbol_table_insert (sym);
703 }
39bec121 704 else
9a736b6b
NC
705 {
706 char *replacement = xmalloc (strlen (name)
1aea3bb8 707 + strlen (stag->name) + 2);
9a736b6b
NC
708 strcpy (replacement, S_GET_NAME (rootsym));
709 strcat (replacement, "+");
710 strcat (replacement, root_stag_name);
711 strcat (replacement, name + strlen (S_GET_NAME (rootsym)));
712 hash_insert (subsym_hash[0], name, replacement);
713 }
39bec121 714
d0313fb7 715 /* Recurse if the field is a structure.
9a736b6b 716 Note the field offset is relative to the outermost struct. */
39bec121 717 if (field->stag != NULL)
9a736b6b
NC
718 stag_add_field_symbols (field->stag, name,
719 field->offset,
720 rootsym, root_stag_name);
39bec121
TW
721 field = field->next;
722 }
723}
724
d0313fb7
NC
725/* Keep track of stag fields so that when structures are nested we can add the
726 complete dereferencing symbols to the symbol table. */
9a736b6b 727
39bec121 728static void
f1e7a2c9
NC
729stag_add_field (parent, name, offset, stag)
730 struct stag *parent;
731 const char *name;
732 bfd_vma offset;
733 struct stag *stag;
39bec121
TW
734{
735 struct stag_field *sfield = xmalloc (sizeof (struct stag_field));
736
737 memset (sfield, 0, sizeof (*sfield));
1aea3bb8 738 sfield->name = strcpy (xmalloc (strlen (name) + 1), name);
39bec121
TW
739 sfield->offset = offset;
740 sfield->bitfield_offset = parent->current_bitfield_offset;
741 sfield->stag = stag;
742 if (parent->field == NULL)
743 parent->field = sfield;
1aea3bb8
NC
744 else
745 {
746 struct stag_field *sf = parent->field;
747 while (sf->next != NULL)
748 sf = sf->next;
749 sf->next = sfield;
750 }
d0313fb7 751 /* Only create a symbol for this field if the parent has no name. */
39bec121
TW
752 if (!strncmp (".fake", parent->name, 5))
753 {
1aea3bb8 754 symbolS *sym = symbol_new (name, absolute_section,
9a736b6b 755 (valueT) offset, &zero_address_frag);
39bec121
TW
756 SF_SET_LOCAL (sym);
757 symbol_table_insert (sym);
758 }
759}
760
761/* [STAG] .struct [OFFSET]
9a736b6b
NC
762 Start defining structure offsets (symbols in absolute section). */
763
39bec121 764static void
f1e7a2c9
NC
765tic54x_struct (arg)
766 int arg;
39bec121
TW
767{
768 int start_offset = 0;
769 int is_union = arg;
770
771 if (!current_stag)
772 {
d0313fb7 773 /* Starting a new struct, switch to absolute section. */
39bec121
TW
774 stag_saved_seg = now_seg;
775 stag_saved_subseg = now_subseg;
776 subseg_set (absolute_section, 0);
777 }
d0313fb7 778 /* Align the current pointer. */
39bec121
TW
779 else if (current_stag->current_bitfield_offset != 0)
780 {
781 ++abs_section_offset;
782 current_stag->current_bitfield_offset = 0;
783 }
784
d0313fb7 785 /* Offset expression is only meaningful for global .structs. */
39bec121
TW
786 if (!is_union)
787 {
d0313fb7 788 /* Offset is ignored in inner structs. */
39bec121 789 SKIP_WHITESPACE ();
1aea3bb8 790 if (!is_end_of_line[(int) *input_line_pointer])
9a736b6b 791 start_offset = get_absolute_expression ();
39bec121 792 else
9a736b6b 793 start_offset = 0;
39bec121
TW
794 }
795
796 if (current_stag)
797 {
d0313fb7 798 /* Nesting, link to outer one. */
1aea3bb8 799 current_stag->inner = (struct stag *) xmalloc (sizeof (struct stag));
39bec121
TW
800 memset (current_stag->inner, 0, sizeof (struct stag));
801 current_stag->inner->outer = current_stag;
802 current_stag = current_stag->inner;
803 if (start_offset)
9a736b6b 804 as_warn (_("Offset on nested structures is ignored"));
39bec121
TW
805 start_offset = abs_section_offset;
806 }
1aea3bb8 807 else
39bec121 808 {
1aea3bb8 809 current_stag = (struct stag *) xmalloc (sizeof (struct stag));
39bec121
TW
810 memset (current_stag, 0, sizeof (struct stag));
811 abs_section_offset = start_offset;
812 }
813 current_stag->is_union = is_union;
814
815 if (line_label == NULL)
816 {
817 static int struct_count = 0;
818 char fake[] = ".fake_stagNNNNNNN";
819 sprintf (fake, ".fake_stag%d", struct_count++);
820 current_stag->sym = symbol_new (fake, absolute_section,
9a736b6b
NC
821 (valueT) abs_section_offset,
822 &zero_address_frag);
39bec121
TW
823 }
824 else
825 {
826 char label[strlen (S_GET_NAME (line_label)) + 1];
827 strcpy (label, S_GET_NAME (line_label));
828 current_stag->sym = symbol_new (label, absolute_section,
9a736b6b
NC
829 (valueT) abs_section_offset,
830 &zero_address_frag);
39bec121
TW
831 }
832 current_stag->name = S_GET_NAME (current_stag->sym);
833 SF_SET_LOCAL (current_stag->sym);
d0313fb7 834 /* Nested .structs don't go into the symbol table. */
39bec121
TW
835 if (current_stag->outer == NULL)
836 symbol_table_insert (current_stag->sym);
837
838 line_label = NULL;
839}
840
1aea3bb8 841/* [LABEL] .endstruct
39bec121 842 finish defining structure offsets; optional LABEL's value will be the size
d0313fb7 843 of the structure. */
9a736b6b 844
39bec121 845static void
f1e7a2c9
NC
846tic54x_endstruct (is_union)
847 int is_union;
39bec121
TW
848{
849 int size;
1aea3bb8 850 const char *path =
39bec121 851 !strncmp (current_stag->name, ".fake", 5) ? "" : current_stag->name;
1aea3bb8 852
39bec121
TW
853 if (!current_stag || current_stag->is_union != is_union)
854 {
1aea3bb8 855 as_bad (_(".end%s without preceding .%s"),
9a736b6b
NC
856 is_union ? "union" : "struct",
857 is_union ? "union" : "struct");
39bec121
TW
858 ignore_rest_of_line ();
859 return;
860 }
861
d0313fb7 862 /* Align end of structures. */
39bec121
TW
863 if (current_stag->current_bitfield_offset)
864 {
865 ++abs_section_offset;
866 current_stag->current_bitfield_offset = 0;
867 }
868
869 if (current_stag->is_union)
870 size = current_stag->size;
871 else
872 size = abs_section_offset - S_GET_VALUE (current_stag->sym);
873 if (line_label != NULL)
874 {
875 S_SET_VALUE (line_label, size);
876 symbol_table_insert (line_label);
877 line_label = NULL;
878 }
879
d0313fb7 880 /* Union size has already been calculated. */
39bec121
TW
881 if (!current_stag->is_union)
882 current_stag->size = size;
d0313fb7 883 /* Nested .structs don't get put in the stag table. */
39bec121
TW
884 if (current_stag->outer == NULL)
885 {
886 hash_insert (stag_hash, current_stag->name, current_stag);
1aea3bb8 887 stag_add_field_symbols (current_stag, path,
9a736b6b
NC
888 S_GET_VALUE (current_stag->sym),
889 NULL, NULL);
39bec121
TW
890 }
891 current_stag = current_stag->outer;
892
d0313fb7
NC
893 /* If this is a nested .struct/.union, add it as a field to the enclosing
894 one. otherwise, restore the section we were in. */
39bec121
TW
895 if (current_stag != NULL)
896 {
897 stag_add_field (current_stag, current_stag->inner->name,
9a736b6b
NC
898 S_GET_VALUE (current_stag->inner->sym),
899 current_stag->inner);
39bec121
TW
900 }
901 else
902 subseg_set (stag_saved_seg, stag_saved_subseg);
903}
904
905/* [LABEL] .tag STAG
906 Reference a structure within a structure, as a sized field with an optional
1aea3bb8 907 label.
39bec121 908 If used outside of a .struct/.endstruct, overlays the given structure
d0313fb7 909 format on the existing allocated space. */
9a736b6b 910
39bec121 911static void
f1e7a2c9
NC
912tic54x_tag (ignore)
913 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
914{
915 char *name = input_line_pointer;
916 int c = get_symbol_end ();
1aea3bb8 917 struct stag *stag = (struct stag *) hash_find (stag_hash, name);
39bec121
TW
918
919 if (!stag)
920 {
921 if (*name)
9a736b6b 922 as_bad (_("Unrecognized struct/union tag '%s'"), name);
39bec121 923 else
9a736b6b 924 as_bad (_(".tag requires a structure tag"));
39bec121
TW
925 ignore_rest_of_line ();
926 return;
927 }
928 if (line_label == NULL)
929 {
930 as_bad (_("Label required for .tag"));
931 ignore_rest_of_line ();
932 return;
933 }
934 else
935 {
1aea3bb8
NC
936 char label[strlen (S_GET_NAME (line_label)) + 1];
937
938 strcpy (label, S_GET_NAME (line_label));
39bec121 939 if (current_stag != NULL)
9a736b6b
NC
940 stag_add_field (current_stag, label,
941 abs_section_offset - S_GET_VALUE (current_stag->sym),
942 stag);
39bec121 943 else
9a736b6b
NC
944 {
945 symbolS *sym = symbol_find (label);
f1e7a2c9 946
9a736b6b
NC
947 if (!sym)
948 {
949 as_bad (_(".tag target '%s' undefined"), label);
950 ignore_rest_of_line ();
951 return;
952 }
953 stag_add_field_symbols (stag, S_GET_NAME (sym),
954 S_GET_VALUE (stag->sym), sym, stag->name);
955 }
39bec121 956 }
1aea3bb8 957
d0313fb7 958 /* Bump by the struct size, but only if we're within a .struct section. */
39bec121
TW
959 if (current_stag != NULL && !current_stag->is_union)
960 abs_section_offset += stag->size;
961
962 *input_line_pointer = c;
963 demand_empty_rest_of_line ();
964 line_label = NULL;
965}
966
d0313fb7 967/* Handle all .byte, .char, .double, .field, .float, .half, .int, .long,
39bec121 968 .short, .string, .ubyte, .uchar, .uhalf, .uint, .ulong, .ushort, .uword,
d0313fb7 969 and .word. */
9a736b6b 970
39bec121 971static void
f1e7a2c9
NC
972tic54x_struct_field (type)
973 int type;
39bec121
TW
974{
975 int size;
976 int count = 1;
977 int new_bitfield_offset = 0;
978 int field_align = current_stag->current_bitfield_offset != 0;
979 int longword_align = 0;
980
981 SKIP_WHITESPACE ();
1aea3bb8 982 if (!is_end_of_line[(int) *input_line_pointer])
39bec121
TW
983 count = get_absolute_expression ();
984
985 switch (type)
986 {
987 case 'b':
988 case 'B':
989 case 'c':
990 case 'C':
991 case 'h':
992 case 'H':
993 case 'i':
994 case 'I':
995 case 's':
996 case 'S':
997 case 'w':
998 case 'W':
9a736b6b 999 case '*': /* String. */
39bec121
TW
1000 size = 1;
1001 break;
1002 case 'f':
1003 case 'l':
1004 case 'L':
1005 longword_align = 1;
1006 size = 2;
1007 break;
9a736b6b 1008 case '.': /* Bitfield. */
39bec121
TW
1009 size = 0;
1010 if (count < 1 || count > 32)
9a736b6b
NC
1011 {
1012 as_bad (_(".field count '%d' out of range (1 <= X <= 32)"), count);
1013 ignore_rest_of_line ();
1014 return;
1015 }
39bec121 1016 if (current_stag->current_bitfield_offset + count > 16)
9a736b6b
NC
1017 {
1018 /* Set the appropriate size and new field offset. */
1019 if (count == 32)
1020 {
1021 size = 2;
1aea3bb8 1022 count = 1;
9a736b6b
NC
1023 }
1024 else if (count > 16)
1025 {
1026 size = 1;
1aea3bb8 1027 count = 1;
9a736b6b
NC
1028 new_bitfield_offset = count - 16;
1029 }
1030 else
f1e7a2c9 1031 new_bitfield_offset = count;
9a736b6b 1032 }
39bec121 1033 else
9a736b6b
NC
1034 {
1035 field_align = 0;
1036 new_bitfield_offset = current_stag->current_bitfield_offset + count;
1037 }
39bec121
TW
1038 break;
1039 default:
1040 as_bad (_("Unrecognized field type '%c'"), type);
1041 ignore_rest_of_line ();
1042 return;
1043 }
1044
1045 if (field_align)
1046 {
d0313fb7 1047 /* Align to the actual starting position of the field. */
39bec121
TW
1048 current_stag->current_bitfield_offset = 0;
1049 ++abs_section_offset;
1050 }
d0313fb7 1051 /* Align to longword boundary. */
39bec121
TW
1052 if (longword_align && (abs_section_offset & 0x1))
1053 ++abs_section_offset;
1054
1055 if (line_label == NULL)
1056 {
1057 static int fieldno = 0;
1058 char fake[] = ".fake_fieldNNNNN";
f1e7a2c9 1059
39bec121 1060 sprintf (fake, ".fake_field%d", fieldno++);
1aea3bb8 1061 stag_add_field (current_stag, fake,
9a736b6b
NC
1062 abs_section_offset - S_GET_VALUE (current_stag->sym),
1063 NULL);
39bec121
TW
1064 }
1065 else
1066 {
1067 char label[strlen (S_GET_NAME (line_label) + 1)];
f1e7a2c9 1068
39bec121 1069 strcpy (label, S_GET_NAME (line_label));
1aea3bb8 1070 stag_add_field (current_stag, label,
9a736b6b
NC
1071 abs_section_offset - S_GET_VALUE (current_stag->sym),
1072 NULL);
39bec121
TW
1073 }
1074
1075 if (current_stag->is_union)
1076 {
d0313fb7 1077 /* Note we treat the element as if it were an array of COUNT. */
1aea3bb8 1078 if (current_stag->size < (unsigned) size * count)
9a736b6b 1079 current_stag->size = size * count;
39bec121
TW
1080 }
1081 else
1082 {
1aea3bb8 1083 abs_section_offset += (unsigned) size * count;
39bec121
TW
1084 current_stag->current_bitfield_offset = new_bitfield_offset;
1085 }
1086 line_label = NULL;
1087}
1088
d0313fb7 1089/* Handle .byte, .word. .int, .long and all variants. */
9a736b6b 1090
1aea3bb8 1091static void
f1e7a2c9
NC
1092tic54x_cons (type)
1093 int type;
39bec121 1094{
f1e7a2c9 1095 unsigned int c;
39bec121
TW
1096 int octets;
1097
d0313fb7 1098 /* If we're within a .struct construct, don't actually allocate space. */
39bec121
TW
1099 if (current_stag != NULL)
1100 {
1101 tic54x_struct_field (type);
1102 return;
1103 }
1104
1105#ifdef md_flush_pending_output
1106 md_flush_pending_output ();
1107#endif
1108
1109 generate_lineno_debug ();
1110
d0313fb7 1111 /* Align long words to long word boundaries (4 octets). */
39bec121
TW
1112 if (type == 'l' || type == 'L')
1113 {
1114 frag_align (2, 0, 2);
d0313fb7 1115 /* If there's a label, assign it to the first allocated word. */
39bec121 1116 if (line_label != NULL)
9a736b6b
NC
1117 {
1118 symbol_set_frag (line_label, frag_now);
1119 S_SET_VALUE (line_label, frag_now_fix ());
1120 }
39bec121
TW
1121 }
1122
1123 switch (type)
1124 {
1125 case 'l':
1126 case 'L':
1127 case 'x':
1128 octets = 4;
1129 break;
1130 case 'b':
1131 case 'B':
1132 case 'c':
1133 case 'C':
1134 octets = 1;
1135 break;
1136 default:
1137 octets = 2;
1138 break;
1139 }
1140
1141 do
1142 {
1143 if (*input_line_pointer == '"')
1144 {
1145 input_line_pointer++;
1146 while (is_a_char (c = next_char_of_string ()))
1147 tic54x_emit_char (c);
1148 know (input_line_pointer[-1] == '\"');
1149 }
1150 else
1151 {
1152 expressionS exp;
1153
1154 input_line_pointer = parse_expression (input_line_pointer, &exp);
1155 if (exp.X_op == O_constant)
1156 {
9a736b6b
NC
1157 offsetT value = exp.X_add_number;
1158 /* Truncate overflows. */
39bec121
TW
1159 switch (octets)
1160 {
1161 case 1:
9a736b6b
NC
1162 if ((value > 0 && value > 0xFF)
1163 || (value < 0 && value < - 0x100))
1164 as_warn ("Overflow in expression, truncated to 8 bits");
39bec121
TW
1165 break;
1166 case 2:
9a736b6b
NC
1167 if ((value > 0 && value > 0xFFFF)
1168 || (value < 0 && value < - 0x10000))
1169 as_warn ("Overflow in expression, truncated to 16 bits");
39bec121
TW
1170 break;
1171 }
1172 }
9a736b6b
NC
1173 if (exp.X_op != O_constant && octets < 2)
1174 {
1175 /* Disallow .byte with a non constant expression that will
1176 require relocation. */
1177 as_bad (_("Relocatable values require at least WORD storage"));
1178 ignore_rest_of_line ();
1179 return;
1180 }
1181
1182 if (exp.X_op != O_constant
1183 && amode == c_mode
1184 && octets == 4)
1185 {
1186 /* FIXME -- at one point TI tools used to output REL16
1187 relocations, but I don't think the latest tools do at all
1188 The current tools output extended relocations regardless of
33b7f697 1189 the addressing mode (I actually think that ".c_mode" is
9a736b6b
NC
1190 totally ignored in the latest tools). */
1191 amode = far_mode;
1192 emitting_long = 1;
1193 emit_expr (&exp, 4);
1194 emitting_long = 0;
1195 amode = c_mode;
1196 }
1197 else
1198 {
1199 emitting_long = octets == 4;
1200 emit_expr (&exp, (octets == 1) ? 2 : octets);
1201 emitting_long = 0;
1202 }
39bec121
TW
1203 }
1204 }
1205 while (*input_line_pointer++ == ',');
1206
1207 input_line_pointer--; /* Put terminator back into stream. */
1208 demand_empty_rest_of_line ();
1209}
1210
1211/* .global <symbol>[,...,<symbolN>]
1212 .def <symbol>[,...,<symbolN>]
1213 .ref <symbol>[,...,<symbolN>]
1214
1aea3bb8 1215 These all identify global symbols.
39bec121
TW
1216
1217 .def means the symbol is defined in the current module and can be accessed
1218 by other files. The symbol should be placed in the symbol table.
1219
1220 .ref means the symbol is used in the current module but defined in another
1221 module. The linker is to resolve this symbol's definition at link time.
1222
1223 .global should act as a .ref or .def, as needed.
1224
1aea3bb8 1225 global, def and ref all have symbol storage classes of C_EXT.
39bec121
TW
1226
1227 I can't identify any difference in how the "other" c54x assembler treats
d0313fb7 1228 these, so we ignore the type here. */
9a736b6b 1229
39bec121 1230void
f1e7a2c9
NC
1231tic54x_global (type)
1232 int type;
39bec121
TW
1233{
1234 char *name;
1235 int c;
1236 symbolS *symbolP;
1237
1238 if (type == 'r')
9a736b6b 1239 as_warn (_("Use of .def/.ref is deprecated. Use .global instead"));
39bec121
TW
1240
1241 ILLEGAL_WITHIN_STRUCT ();
1242
1243 do
1244 {
1245 name = input_line_pointer;
1246 c = get_symbol_end ();
1247 symbolP = symbol_find_or_make (name);
1248
1249 *input_line_pointer = c;
1250 S_SET_STORAGE_CLASS (symbolP, C_EXT);
1251 if (c == ',')
1252 {
1253 input_line_pointer++;
1aea3bb8 1254 if (is_end_of_line[(int) *input_line_pointer])
39bec121
TW
1255 c = *input_line_pointer;
1256 }
1257 }
1258 while (c == ',');
1259
1260 demand_empty_rest_of_line ();
1261}
1262
d0313fb7 1263/* Remove the symbol from the local label hash lookup. */
9a736b6b 1264
39bec121 1265static void
f1e7a2c9
NC
1266tic54x_remove_local_label (key, value)
1267 const char *key;
1268 PTR value ATTRIBUTE_UNUSED;
39bec121
TW
1269{
1270 PTR *elem = hash_delete (local_label_hash[macro_level], key);
1271 free (elem);
1272}
1273
d0313fb7 1274/* Reset all local labels. */
9a736b6b 1275
1aea3bb8 1276static void
f1e7a2c9
NC
1277tic54x_clear_local_labels (ignored)
1278 int ignored ATTRIBUTE_UNUSED;
39bec121
TW
1279{
1280 hash_traverse (local_label_hash[macro_level], tic54x_remove_local_label);
1281}
1282
d0313fb7 1283/* .text
39bec121
TW
1284 .data
1285 .sect "section name"
1286
1287 Initialized section
1aea3bb8 1288 make sure local labels get cleared when changing sections
39bec121
TW
1289
1290 ARG is 't' for text, 'd' for data, or '*' for a named section
1291
6e917903
TW
1292 For compatibility, '*' sections are SEC_CODE if instructions are
1293 encountered, or SEC_DATA if not.
1294*/
9a736b6b 1295
39bec121 1296static void
f1e7a2c9
NC
1297tic54x_sect (arg)
1298 int arg;
39bec121
TW
1299{
1300 ILLEGAL_WITHIN_STRUCT ();
1301
d0313fb7 1302 /* Local labels are cleared when changing sections. */
39bec121
TW
1303 tic54x_clear_local_labels (0);
1304
1305 if (arg == 't')
1306 s_text (0);
1307 else if (arg == 'd')
1308 s_data (0);
1309 else
1310 {
1311 char *name = NULL;
1312 int len;
f1e7a2c9 1313
d0313fb7 1314 /* If there are quotes, remove them. */
39bec121 1315 if (*input_line_pointer == '"')
9a736b6b
NC
1316 {
1317 name = demand_copy_C_string (&len);
1318 demand_empty_rest_of_line ();
1319 name = strcpy (xmalloc (len + 10), name);
1320 }
1aea3bb8 1321 else
9a736b6b
NC
1322 {
1323 int c;
1324 name = input_line_pointer;
1325 c = get_symbol_end ();
6e917903 1326 len = strlen(name);
9a736b6b
NC
1327 name = strcpy (xmalloc (len + 10), name);
1328 *input_line_pointer = c;
1329 demand_empty_rest_of_line ();
1330 }
6e917903 1331 /* Make sure all named initialized sections flagged properly. If we
f1e7a2c9 1332 encounter instructions, we'll flag it with SEC_CODE as well. */
39bec121
TW
1333 strcat (name, ",\"w\"\n");
1334 input_scrub_insert_line (name);
1335 obj_coff_section (0);
1336
d0313fb7 1337 /* If there was a line label, make sure that it gets assigned the proper
9a736b6b
NC
1338 section. This is for compatibility, even though the actual behavior
1339 is not explicitly defined. For consistency, we make .sect behave
1340 like .usect, since that is probably what people expect. */
39bec121 1341 if (line_label != NULL)
9a736b6b
NC
1342 {
1343 S_SET_SEGMENT (line_label, now_seg);
1344 symbol_set_frag (line_label, frag_now);
1345 S_SET_VALUE (line_label, frag_now_fix ());
1346 if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
1347 S_SET_STORAGE_CLASS (line_label, C_LABEL);
1348 }
39bec121
TW
1349 }
1350}
1351
1aea3bb8 1352/* [symbol] .space space_in_bits
39bec121 1353 [symbol] .bes space_in_bits
1aea3bb8 1354 BES puts the symbol at the *last* word allocated
39bec121 1355
d0313fb7 1356 cribbed from s_space. */
9a736b6b 1357
39bec121 1358static void
f1e7a2c9
NC
1359tic54x_space (arg)
1360 int arg;
39bec121
TW
1361{
1362 expressionS exp;
1363 char *p = 0;
1364 int octets = 0;
1365 long words;
1366 int bits_per_byte = (OCTETS_PER_BYTE * 8);
1367 int bit_offset = 0;
1368 symbolS *label = line_label;
1369 int bes = arg;
1370
1371 ILLEGAL_WITHIN_STRUCT ();
1372
1373#ifdef md_flush_pending_output
1374 md_flush_pending_output ();
1375#endif
1376
d0313fb7 1377 /* Read the bit count. */
39bec121
TW
1378 expression (&exp);
1379
d0313fb7 1380 /* Some expressions are unresolvable until later in the assembly pass;
39bec121 1381 postpone until relaxation/fixup. we also have to postpone if a previous
d0313fb7 1382 partial allocation has not been completed yet. */
39bec121
TW
1383 if (exp.X_op != O_constant || frag_bit_offset (frag_now, now_seg) == -1)
1384 {
1385 struct bit_info *bi = xmalloc (sizeof (struct bit_info));
1386 char *p;
1387
1388 bi->seg = now_seg;
1389 bi->type = bes;
1390 bi->sym = label;
1aea3bb8 1391 p = frag_var (rs_machine_dependent,
9a736b6b
NC
1392 65536 * 2, 1, (relax_substateT) 0,
1393 make_expr_symbol (&exp), (offsetT) 0,
1394 (char *) bi);
39bec121 1395 if (p)
9a736b6b 1396 *p = 0;
39bec121
TW
1397
1398 return;
1399 }
1400
d0313fb7
NC
1401 /* Reduce the required size by any bit offsets currently left over
1402 from a previous .space/.bes/.field directive. */
39bec121
TW
1403 bit_offset = frag_now->tc_frag_data;
1404 if (bit_offset != 0 && bit_offset < 16)
1405 {
1406 int spare_bits = bits_per_byte - bit_offset;
f1e7a2c9 1407
39bec121 1408 if (spare_bits >= exp.X_add_number)
9a736b6b
NC
1409 {
1410 /* Don't have to do anything; sufficient bits have already been
1411 allocated; just point the label to the right place. */
1412 if (label != NULL)
1413 {
1414 symbol_set_frag (label, frag_now);
1415 S_SET_VALUE (label, frag_now_fix () - 1);
1416 label = NULL;
1417 }
1418 frag_now->tc_frag_data += exp.X_add_number;
1419 goto getout;
1420 }
39bec121 1421 exp.X_add_number -= spare_bits;
d0313fb7 1422 /* Set the label to point to the first word allocated, which in this
9a736b6b 1423 case is the previous word, which was only partially filled. */
39bec121 1424 if (!bes && label != NULL)
9a736b6b
NC
1425 {
1426 symbol_set_frag (label, frag_now);
1427 S_SET_VALUE (label, frag_now_fix () - 1);
1428 label = NULL;
1429 }
39bec121 1430 }
d0313fb7 1431 /* Convert bits to bytes/words and octets, rounding up. */
39bec121 1432 words = ((exp.X_add_number + bits_per_byte - 1) / bits_per_byte);
d0313fb7 1433 /* How many do we have left over? */
39bec121
TW
1434 bit_offset = exp.X_add_number % bits_per_byte;
1435 octets = words * OCTETS_PER_BYTE;
1436 if (octets < 0)
1437 {
1438 as_warn (_(".space/.bes repeat count is negative, ignored"));
1439 goto getout;
1440 }
1441 else if (octets == 0)
1442 {
1443 as_warn (_(".space/.bes repeat count is zero, ignored"));
1444 goto getout;
1445 }
1aea3bb8 1446
39bec121
TW
1447 /* If we are in the absolute section, just bump the offset. */
1448 if (now_seg == absolute_section)
1449 {
1450 abs_section_offset += words;
1451 if (bes && label != NULL)
9a736b6b 1452 S_SET_VALUE (label, abs_section_offset - 1);
39bec121
TW
1453 frag_now->tc_frag_data = bit_offset;
1454 goto getout;
1455 }
1aea3bb8 1456
39bec121 1457 if (!need_pass_2)
1aea3bb8 1458 p = frag_var (rs_fill, 1, 1,
9a736b6b
NC
1459 (relax_substateT) 0, (symbolS *) 0,
1460 (offsetT) octets, (char *) 0);
39bec121 1461
d0313fb7 1462 /* Make note of how many bits of this word we've allocated so far. */
39bec121
TW
1463 frag_now->tc_frag_data = bit_offset;
1464
d0313fb7 1465 /* .bes puts label at *last* word allocated. */
39bec121
TW
1466 if (bes && label != NULL)
1467 {
1468 symbol_set_frag (label, frag_now);
1aea3bb8 1469 S_SET_VALUE (label, frag_now_fix () - 1);
39bec121 1470 }
1aea3bb8 1471
39bec121
TW
1472 if (p)
1473 *p = 0;
1474
1475 getout:
1476
1477 demand_empty_rest_of_line ();
1478}
1479
1aea3bb8 1480/* [symbol] .usect "section-name", size-in-words
9a736b6b 1481 [, [blocking-flag] [, alignment-flag]]
39bec121 1482
33b7f697 1483 Uninitialized section.
39bec121
TW
1484 Non-zero blocking means that if the section would cross a page (128-word)
1485 boundary, it will be page-aligned.
1486 Non-zero alignment aligns on a longword boundary.
1487
d0313fb7 1488 Has no effect on the current section. */
9a736b6b 1489
1aea3bb8 1490static void
f1e7a2c9
NC
1491tic54x_usect (x)
1492 int x ATTRIBUTE_UNUSED;
39bec121
TW
1493{
1494 char c;
1495 char *name;
1496 char *section_name;
1497 char *p;
1498 segT seg;
1499 int size, blocking_flag, alignment_flag;
1500 segT current_seg;
1501 subsegT current_subseg;
1502 flagword flags;
1503
1504 ILLEGAL_WITHIN_STRUCT ();
1505
9a736b6b
NC
1506 current_seg = now_seg; /* Save current seg. */
1507 current_subseg = now_subseg; /* Save current subseg. */
39bec121
TW
1508
1509 if (*input_line_pointer == '"')
1510 input_line_pointer++;
1511 section_name = input_line_pointer;
1512 c = get_symbol_end (); /* Get terminator. */
1513 input_line_pointer++; /* Skip null symbol terminator. */
1514 name = xmalloc (input_line_pointer - section_name + 1);
1515 strcpy (name, section_name);
1516
1517 if (*input_line_pointer == ',')
1518 ++input_line_pointer;
1519 else if (c != ',')
1520 {
1521 as_bad (_("Missing size argument"));
1522 ignore_rest_of_line ();
1523 return;
1524 }
1525
1526 size = get_absolute_expression ();
1527
d0313fb7 1528 /* Read a possibly present third argument (blocking flag). */
39bec121
TW
1529 if (*input_line_pointer == ',')
1530 {
1531 ++input_line_pointer;
1532 if (*input_line_pointer != ',')
9a736b6b 1533 blocking_flag = get_absolute_expression ();
39bec121 1534 else
9a736b6b 1535 blocking_flag = 0;
39bec121 1536
d0313fb7 1537 /* Read a possibly present fourth argument (alignment flag). */
39bec121 1538 if (*input_line_pointer == ',')
9a736b6b
NC
1539 {
1540 ++input_line_pointer;
1541 alignment_flag = get_absolute_expression ();
1542 }
39bec121 1543 else
9a736b6b 1544 alignment_flag = 0;
39bec121
TW
1545 }
1546 else
1547 blocking_flag = alignment_flag = 0;
1548
1549 seg = subseg_new (name, 0);
1550 flags = bfd_get_section_flags (stdoutput, seg) | SEC_ALLOC;
1551
1552 if (alignment_flag)
1553 {
d0313fb7 1554 /* s_align eats end of line; restore it. */
39bec121
TW
1555 s_align_bytes (4);
1556 --input_line_pointer;
1557 }
1558
1559 if (line_label != NULL)
1560 {
1561 S_SET_SEGMENT (line_label, seg);
1562 symbol_set_frag (line_label, frag_now);
1563 S_SET_VALUE (line_label, frag_now_fix ());
9a736b6b 1564 /* Set scl to label, since that's what TI does. */
39bec121 1565 if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
9a736b6b 1566 S_SET_STORAGE_CLASS (line_label, C_LABEL);
39bec121
TW
1567 }
1568
1569 seg_info (seg)->bss = 1; /* Uninitialized data. */
1570
1aea3bb8 1571 p = frag_var (rs_fill, 1, 1,
9a736b6b
NC
1572 (relax_substateT) 0, (symbolS *) line_label,
1573 size * OCTETS_PER_BYTE, (char *) 0);
39bec121
TW
1574 *p = 0;
1575
1576 if (blocking_flag)
1577 flags |= SEC_BLOCK;
1578
1579 if (!bfd_set_section_flags (stdoutput, seg, flags))
1580 as_warn ("Error setting flags for \"%s\": %s", name,
1581 bfd_errmsg (bfd_get_error ()));
1582
1583 subseg_set (current_seg, current_subseg); /* Restore current seg. */
1584 demand_empty_rest_of_line ();
1aea3bb8 1585}
39bec121
TW
1586
1587static enum cpu_version
f1e7a2c9
NC
1588lookup_version (ver)
1589 const char *ver;
39bec121
TW
1590{
1591 enum cpu_version version = VNONE;
1aea3bb8 1592
39bec121
TW
1593 if (ver[0] == '5' && ver[1] == '4')
1594 {
9a736b6b
NC
1595 if (strlen (ver) == 3
1596 && (ver[2] == '1' || ver[2] == '2' || ver[2] == '3'
1597 || ver[2] == '5' || ver[2] == '8' || ver[2] == '9'))
1598 version = ver[2] - '0';
1599 else if (strlen (ver) == 5
3882b010
L
1600 && TOUPPER (ver[3]) == 'L'
1601 && TOUPPER (ver[4]) == 'P'
9a736b6b
NC
1602 && (ver[2] == '5' || ver[2] == '6'))
1603 version = ver[2] - '0' + 10;
39bec121
TW
1604 }
1605
1606 return version;
1607}
1608
1609static void
f1e7a2c9
NC
1610set_cpu (version)
1611 enum cpu_version version;
39bec121
TW
1612{
1613 cpu = version;
1614 if (version == V545LP || version == V546LP)
1615 {
1616 symbolS *symbolP = symbol_new ("__allow_lp", absolute_section,
9a736b6b 1617 (valueT) 1, &zero_address_frag);
39bec121
TW
1618 SF_SET_LOCAL (symbolP);
1619 symbol_table_insert (symbolP);
1620 }
1621}
1622
1aea3bb8 1623/* .version cpu-version
39bec121
TW
1624 cpu-version may be one of the following:
1625 541
1626 542
1627 543
1628 545
1629 545LP
1630 546LP
1631 548
1632 549
1633
d0313fb7 1634 This is for compatibility only. It currently has no affect on assembly. */
39bec121 1635static int cpu_needs_set = 1;
d0313fb7 1636
1aea3bb8 1637static void
f1e7a2c9
NC
1638tic54x_version (x)
1639 int x ATTRIBUTE_UNUSED;
39bec121
TW
1640{
1641 enum cpu_version version = VNONE;
1642 enum cpu_version old_version = cpu;
1643 int c;
1644 char *ver;
1645
1646 ILLEGAL_WITHIN_STRUCT ();
1647
1648 SKIP_WHITESPACE ();
1649 ver = input_line_pointer;
1aea3bb8 1650 while (!is_end_of_line[(int) *input_line_pointer])
39bec121
TW
1651 ++input_line_pointer;
1652 c = *input_line_pointer;
1653 *input_line_pointer = 0;
1aea3bb8 1654
39bec121
TW
1655 version = lookup_version (ver);
1656
1657 if (cpu != VNONE && cpu != version)
1658 as_warn (_("CPU version has already been set"));
1659
1660 if (version == VNONE)
1661 {
1662 as_bad (_("Unrecognized version '%s'"), ver);
1663 ignore_rest_of_line ();
1664 return;
1665 }
1666 else if (assembly_begun && version != old_version)
1667 {
1668 as_bad (_("Changing of CPU version on the fly not supported"));
1669 ignore_rest_of_line ();
1670 return;
1671 }
1672
1673 set_cpu (version);
1674
1675 *input_line_pointer = c;
1676 demand_empty_rest_of_line ();
1677}
1678
d0313fb7 1679/* 'f' = float, 'x' = xfloat, 'd' = double, 'l' = ldouble. */
9a736b6b 1680
39bec121 1681static void
f1e7a2c9
NC
1682tic54x_float_cons (type)
1683 int type;
39bec121
TW
1684{
1685 if (current_stag != 0)
d0313fb7 1686 tic54x_struct_field ('f');
39bec121
TW
1687
1688#ifdef md_flush_pending_output
1689 md_flush_pending_output ();
1690#endif
1aea3bb8 1691
d0313fb7 1692 /* Align to long word boundary (4 octets) unless it's ".xfloat". */
39bec121
TW
1693 if (type != 'x')
1694 {
1695 frag_align (2, 0, 2);
d0313fb7 1696 /* If there's a label, assign it to the first allocated word. */
39bec121 1697 if (line_label != NULL)
9a736b6b
NC
1698 {
1699 symbol_set_frag (line_label, frag_now);
1700 S_SET_VALUE (line_label, frag_now_fix ());
1701 }
39bec121
TW
1702 }
1703
1704 float_cons ('f');
1705}
1706
1aea3bb8 1707/* The argument is capitalized if it should be zero-terminated
39bec121 1708 's' is normal string with upper 8-bits zero-filled, 'p' is packed.
5d6255fe 1709 Code copied from stringer, and slightly modified so that strings are packed
d0313fb7 1710 and encoded into the correct octets. */
9a736b6b 1711
39bec121 1712static void
f1e7a2c9
NC
1713tic54x_stringer (type)
1714 int type;
39bec121 1715{
f1e7a2c9 1716 unsigned int c;
39bec121
TW
1717 char *start;
1718 int append_zero = type == 'S' || type == 'P';
1719 int packed = type == 'p' || type == 'P';
d0313fb7 1720 int last_char = -1; /* Packed strings need two bytes at a time to encode. */
39bec121
TW
1721
1722 if (current_stag != NULL)
1723 {
1724 tic54x_struct_field ('*');
1725 return;
1726 }
1727
1728#ifdef md_flush_pending_output
1729 md_flush_pending_output ();
1730#endif
1731
1dab94dd 1732 c = ','; /* Do loop. */
39bec121
TW
1733 while (c == ',')
1734 {
1735 SKIP_WHITESPACE ();
1736 switch (*input_line_pointer)
1737 {
9a736b6b
NC
1738 default:
1739 {
1740 unsigned short value = get_absolute_expression ();
1741 FRAG_APPEND_1_CHAR ( value & 0xFF);
1742 FRAG_APPEND_1_CHAR ((value >> 8) & 0xFF);
1743 break;
1744 }
39bec121 1745 case '\"':
9a736b6b 1746 ++input_line_pointer; /* -> 1st char of string. */
39bec121
TW
1747 start = input_line_pointer;
1748 while (is_a_char (c = next_char_of_string ()))
1749 {
9a736b6b
NC
1750 if (!packed)
1751 {
1752 FRAG_APPEND_1_CHAR (c);
1753 FRAG_APPEND_1_CHAR (0);
1754 }
1755 else
1756 {
1757 /* Packed strings are filled MS octet first. */
1758 if (last_char == -1)
1759 last_char = c;
1760 else
1761 {
1762 FRAG_APPEND_1_CHAR (c);
1763 FRAG_APPEND_1_CHAR (last_char);
1764 last_char = -1;
1765 }
1766 }
39bec121
TW
1767 }
1768 if (append_zero)
9a736b6b
NC
1769 {
1770 if (packed && last_char != -1)
1771 {
1772 FRAG_APPEND_1_CHAR (0);
1773 FRAG_APPEND_1_CHAR (last_char);
1774 last_char = -1;
1775 }
1776 else
1777 {
1778 FRAG_APPEND_1_CHAR (0);
1779 FRAG_APPEND_1_CHAR (0);
1780 }
1781 }
39bec121
TW
1782 know (input_line_pointer[-1] == '\"');
1783 break;
1784 }
1785 SKIP_WHITESPACE ();
1786 c = *input_line_pointer;
1787 if (!is_end_of_line[c])
9a736b6b 1788 ++input_line_pointer;
39bec121
TW
1789 }
1790
d0313fb7 1791 /* Finish up any leftover packed string. */
39bec121
TW
1792 if (packed && last_char != -1)
1793 {
1794 FRAG_APPEND_1_CHAR (0);
1795 FRAG_APPEND_1_CHAR (last_char);
1796 }
1797 demand_empty_rest_of_line ();
1798}
1799
1800static void
f1e7a2c9
NC
1801tic54x_p2align (arg)
1802 int arg ATTRIBUTE_UNUSED;
39bec121
TW
1803{
1804 as_bad (_("p2align not supported on this target"));
1805}
1806
1807static void
f1e7a2c9
NC
1808tic54x_align_words (arg)
1809 int arg;
39bec121 1810{
d0313fb7 1811 /* Only ".align" with no argument is allowed within .struct/.union. */
39bec121
TW
1812 int count = arg;
1813
1aea3bb8 1814 if (!is_end_of_line[(int) *input_line_pointer])
39bec121
TW
1815 {
1816 if (arg == 2)
9a736b6b 1817 as_warn (_("Argument to .even ignored"));
39bec121 1818 else
9a736b6b 1819 count = get_absolute_expression ();
39bec121
TW
1820 }
1821
1822 if (current_stag != NULL && arg == 128)
1823 {
1824 if (current_stag->current_bitfield_offset != 0)
9a736b6b
NC
1825 {
1826 current_stag->current_bitfield_offset = 0;
1827 ++abs_section_offset;
1828 }
39bec121
TW
1829 demand_empty_rest_of_line ();
1830 return;
1831 }
1832
1833 ILLEGAL_WITHIN_STRUCT ();
1834
1835 s_align_bytes (count << 1);
1836}
1837
d0313fb7 1838/* Initialize multiple-bit fields withing a single word of memory. */
9a736b6b 1839
39bec121 1840static void
f1e7a2c9
NC
1841tic54x_field (ignore)
1842 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
1843{
1844 expressionS exp;
1845 int size = 16;
1846 char *p;
1847 valueT value;
1848 symbolS *label = line_label;
1849
1850 if (current_stag != NULL)
1851 {
1852 tic54x_struct_field ('.');
1853 return;
1854 }
1855
1856 input_line_pointer = parse_expression (input_line_pointer, &exp);
1857
1858 if (*input_line_pointer == ',')
1859 {
1860 ++input_line_pointer;
1861 size = get_absolute_expression ();
1862 if (size < 1 || size > 32)
9a736b6b
NC
1863 {
1864 as_bad (_("Invalid field size, must be from 1 to 32"));
1865 ignore_rest_of_line ();
1866 return;
1867 }
39bec121
TW
1868 }
1869
d0313fb7 1870 /* Truncate values to the field width. */
39bec121
TW
1871 if (exp.X_op != O_constant)
1872 {
9a736b6b
NC
1873 /* If the expression value is relocatable, the field size *must*
1874 be 16. */
39bec121 1875 if (size != 16)
9a736b6b
NC
1876 {
1877 as_bad (_("field size must be 16 when value is relocatable"));
1878 ignore_rest_of_line ();
1879 return;
1880 }
39bec121
TW
1881
1882 frag_now->tc_frag_data = 0;
1883 emit_expr (&exp, 2);
1884 }
1885 else
1886 {
1887 unsigned long fmask = (size == 32) ? 0xFFFFFFFF : (1ul << size) - 1;
f1e7a2c9 1888
39bec121
TW
1889 value = exp.X_add_number;
1890 exp.X_add_number &= fmask;
1aea3bb8 1891 if (value != (valueT) exp.X_add_number)
9a736b6b 1892 as_warn (_("field value truncated"));
39bec121 1893 value = exp.X_add_number;
d0313fb7 1894 /* Bits are stored MS first. */
39bec121 1895 while (size >= 16)
9a736b6b
NC
1896 {
1897 frag_now->tc_frag_data = 0;
1898 p = frag_more (2);
1899 md_number_to_chars (p, (value >> (size - 16)) & 0xFFFF, 2);
1900 size -= 16;
1901 }
39bec121 1902 if (size > 0)
9a736b6b
NC
1903 {
1904 int bit_offset = frag_bit_offset (frag_now, now_seg);
f1e7a2c9 1905
9a736b6b
NC
1906 fragS *alloc_frag = bit_offset_frag (frag_now, now_seg);
1907 if (bit_offset == -1)
1908 {
1909 struct bit_info *bi = xmalloc (sizeof (struct bit_info));
1910 /* We don't know the previous offset at this time, so store the
1911 info we need and figure it out later. */
1912 expressionS size_exp;
f1e7a2c9 1913
9a736b6b
NC
1914 size_exp.X_op = O_constant;
1915 size_exp.X_add_number = size;
1916 bi->seg = now_seg;
1917 bi->type = TYPE_FIELD;
1918 bi->value = value;
1919 p = frag_var (rs_machine_dependent,
1920 4, 1, (relax_substateT) 0,
1921 make_expr_symbol (&size_exp), (offsetT) 0,
1922 (char *) bi);
1923 goto getout;
1924 }
1925 else if (bit_offset == 0 || bit_offset + size > 16)
1926 {
1927 /* Align a new field. */
1928 p = frag_more (2);
1929 frag_now->tc_frag_data = 0;
1930 alloc_frag = frag_now;
1931 }
1932 else
1933 {
1934 /* Put the new value entirely within the existing one. */
1935 p = alloc_frag == frag_now ?
1936 frag_now->fr_literal + frag_now_fix_octets () - 2 :
1937 alloc_frag->fr_literal;
1938 if (label != NULL)
1939 {
1940 symbol_set_frag (label, alloc_frag);
1941 if (alloc_frag == frag_now)
1942 S_SET_VALUE (label, frag_now_fix () - 1);
1943 label = NULL;
1944 }
1945 }
1946 value <<= 16 - alloc_frag->tc_frag_data - size;
1947
1948 /* OR in existing value. */
1949 if (alloc_frag->tc_frag_data)
1950 value |= ((unsigned short) p[1] << 8) | p[0];
1951 md_number_to_chars (p, value, 2);
1952 alloc_frag->tc_frag_data += size;
1953 if (alloc_frag->tc_frag_data == 16)
1954 alloc_frag->tc_frag_data = 0;
1955 }
39bec121
TW
1956 }
1957 getout:
1958 demand_empty_rest_of_line ();
1959}
1960
1961/* Ideally, we want to check SEC_LOAD and SEC_HAS_CONTENTS, but those aren't
d0313fb7 1962 available yet. seg_info ()->bss is the next best thing. */
9a736b6b 1963
39bec121 1964static int
f1e7a2c9
NC
1965tic54x_initialized_section (seg)
1966 segT seg;
39bec121
TW
1967{
1968 return !seg_info (seg)->bss;
1969}
1970
1aea3bb8 1971/* .clink ["section name"]
39bec121
TW
1972
1973 Marks the section as conditionally linked (link only if contents are
1974 referenced elsewhere.
1975 Without a name, refers to the current initialized section.
d0313fb7 1976 Name is required for uninitialized sections. */
9a736b6b 1977
39bec121 1978static void
f1e7a2c9
NC
1979tic54x_clink (ignored)
1980 int ignored ATTRIBUTE_UNUSED;
39bec121
TW
1981{
1982 segT seg = now_seg;
1983
1984 ILLEGAL_WITHIN_STRUCT ();
1985
1986 if (*input_line_pointer == '\"')
1987 {
1988 char *section_name = ++input_line_pointer;
1989 char *name;
f1e7a2c9 1990
39bec121 1991 while (is_a_char (next_char_of_string ()))
9a736b6b 1992 ;
39bec121
TW
1993 know (input_line_pointer[-1] == '\"');
1994 input_line_pointer[-1] = 0;
1995 name = xmalloc (input_line_pointer - section_name + 1);
1996 strcpy (name, section_name);
1997
1998 seg = bfd_get_section_by_name (stdoutput, name);
1999 if (seg == NULL)
9a736b6b
NC
2000 {
2001 as_bad (_("Unrecognized section '%s'"), section_name);
2002 ignore_rest_of_line ();
2003 return;
2004 }
39bec121
TW
2005 }
2006 else
2007 {
2008 if (!tic54x_initialized_section (seg))
9a736b6b
NC
2009 {
2010 as_bad (_("Current section is unitialized, "
2011 "section name required for .clink"));
2012 ignore_rest_of_line ();
2013 return;
2014 }
39bec121
TW
2015 }
2016
2017 seg->flags |= SEC_CLINK;
2018
2019 demand_empty_rest_of_line ();
2020}
2021
d0313fb7 2022/* Change the default include directory to be the current source file's
39bec121 2023 directory, instead of the current working directory. If DOT is non-zero,
d0313fb7 2024 set to "." instead. */
9a736b6b 2025
39bec121 2026static void
f1e7a2c9
NC
2027tic54x_set_default_include (dot)
2028 int dot;
39bec121
TW
2029{
2030 char *dir = ".";
2031 char *tmp = NULL;
1aea3bb8 2032
39bec121
TW
2033 if (!dot)
2034 {
2035 char *curfile;
2036 unsigned lineno;
1aea3bb8 2037
39bec121 2038 as_where (&curfile, &lineno);
1aea3bb8 2039 dir = strcpy (xmalloc (strlen (curfile) + 1), curfile);
39bec121
TW
2040 tmp = strrchr (dir, '/');
2041 }
2042 if (tmp != NULL)
2043 {
2044 int len;
f1e7a2c9 2045
39bec121
TW
2046 *tmp = '\0';
2047 len = strlen (dir);
2048 if (include_dir_count == 0)
9a736b6b
NC
2049 {
2050 include_dirs = (char **) xmalloc (sizeof (*include_dirs));
2051 include_dir_count = 1;
2052 }
39bec121
TW
2053 include_dirs[0] = dir;
2054 if (len > include_dir_maxlen)
9a736b6b 2055 include_dir_maxlen = len;
39bec121
TW
2056 }
2057 else if (include_dirs != NULL)
2058 include_dirs[0] = ".";
2059}
2060
1aea3bb8 2061/* .include "filename" | filename
39bec121
TW
2062 .copy "filename" | filename
2063
1aea3bb8 2064 FIXME 'include' file should be omitted from any output listing,
39bec121
TW
2065 'copy' should be included in any output listing
2066 FIXME -- prevent any included files from changing listing (compat only)
2067 FIXME -- need to include source file directory in search path; what's a
2068 good way to do this?
2069
d0313fb7 2070 Entering/exiting included/copied file clears all local labels. */
9a736b6b 2071
39bec121 2072static void
f1e7a2c9
NC
2073tic54x_include (ignored)
2074 int ignored ATTRIBUTE_UNUSED;
39bec121
TW
2075{
2076 char newblock[] = " .newblock\n";
2077 char *filename;
2078 char *input;
2079 int len, c = -1;
2080
2081 ILLEGAL_WITHIN_STRUCT ();
1aea3bb8 2082
39bec121
TW
2083 SKIP_WHITESPACE ();
2084
2085 if (*input_line_pointer == '"')
2086 {
2087 filename = demand_copy_C_string (&len);
2088 demand_empty_rest_of_line ();
2089 }
2090 else
2091 {
2092 filename = input_line_pointer;
1aea3bb8 2093 while (!is_end_of_line[(int) *input_line_pointer])
9a736b6b 2094 ++input_line_pointer;
39bec121
TW
2095 c = *input_line_pointer;
2096 *input_line_pointer = '\0';
1aea3bb8 2097 filename = strcpy (xmalloc (strlen (filename) + 1), filename);
39bec121
TW
2098 *input_line_pointer = c;
2099 demand_empty_rest_of_line ();
2100 }
2101 /* Insert a partial line with the filename (for the sake of s_include)
2102 and a .newblock.
2103 The included file will be inserted before the newblock, so that the
d0313fb7 2104 newblock is executed after the included file is processed. */
39bec121
TW
2105 input = xmalloc (sizeof (newblock) + strlen (filename) + 4);
2106 sprintf (input, "\"%s\"\n%s", filename, newblock);
2107 input_scrub_insert_line (input);
2108
2109 tic54x_clear_local_labels (0);
2110
2111 tic54x_set_default_include (0);
2112
2113 s_include (0);
2114}
2115
2116static void
f1e7a2c9
NC
2117tic54x_message (type)
2118 int type;
39bec121
TW
2119{
2120 char *msg;
2121 char c;
2122 int len;
2123
2124 ILLEGAL_WITHIN_STRUCT ();
2125
2126 if (*input_line_pointer == '"')
2127 msg = demand_copy_C_string (&len);
2128 else
2129 {
2130 msg = input_line_pointer;
1aea3bb8 2131 while (!is_end_of_line[(int) *input_line_pointer])
9a736b6b 2132 ++input_line_pointer;
39bec121
TW
2133 c = *input_line_pointer;
2134 *input_line_pointer = 0;
2135 msg = strcpy (xmalloc (strlen (msg) + 1), msg);
2136 *input_line_pointer = c;
2137 }
2138
2139 switch (type)
2140 {
2141 case 'm':
2142 as_tsktsk ("%s", msg);
2143 break;
2144 case 'w':
2145 as_warn ("%s", msg);
2146 break;
2147 case 'e':
2148 as_bad ("%s", msg);
2149 break;
2150 }
2151
2152 demand_empty_rest_of_line ();
2153}
2154
1aea3bb8 2155/* .label <symbol>
9a736b6b 2156 Define a special symbol that refers to the loadtime address rather than the
39bec121
TW
2157 runtime address within the current section.
2158
2159 This symbol gets a special storage class so that when it is resolved, it is
2160 resolved relative to the load address (lma) of the section rather than the
d0313fb7 2161 run address (vma). */
9a736b6b 2162
39bec121 2163static void
f1e7a2c9
NC
2164tic54x_label (ignored)
2165 int ignored ATTRIBUTE_UNUSED;
39bec121
TW
2166{
2167 char *name = input_line_pointer;
2168 symbolS *symbolP;
2169 int c;
2170
2171 ILLEGAL_WITHIN_STRUCT ();
2172
2173 c = get_symbol_end ();
2174 symbolP = colon (name);
2175 S_SET_STORAGE_CLASS (symbolP, C_STATLAB);
2176
2177 *input_line_pointer = c;
2178 demand_empty_rest_of_line ();
2179}
2180
d0313fb7 2181/* .mmregs
9a736b6b
NC
2182 Install all memory-mapped register names into the symbol table as
2183 absolute local symbols. */
2184
39bec121 2185static void
f1e7a2c9
NC
2186tic54x_mmregs (ignored)
2187 int ignored ATTRIBUTE_UNUSED;
39bec121
TW
2188{
2189 symbol *sym;
2190
2191 ILLEGAL_WITHIN_STRUCT ();
2192
1aea3bb8 2193 for (sym = (symbol *) mmregs; sym->name; sym++)
39bec121
TW
2194 {
2195 symbolS *symbolP = symbol_new (sym->name, absolute_section,
9a736b6b 2196 (valueT) sym->value, &zero_address_frag);
39bec121
TW
2197 SF_SET_LOCAL (symbolP);
2198 symbol_table_insert (symbolP);
2199 }
2200}
2201
d0313fb7 2202/* .loop [count]
9a736b6b
NC
2203 Count defaults to 1024. */
2204
39bec121 2205static void
f1e7a2c9
NC
2206tic54x_loop (count)
2207 int count;
39bec121
TW
2208{
2209 ILLEGAL_WITHIN_STRUCT ();
2210
2211 SKIP_WHITESPACE ();
1aea3bb8 2212 if (!is_end_of_line[(int) *input_line_pointer])
9a736b6b 2213 count = get_absolute_expression ();
39bec121
TW
2214
2215 do_repeat (count, "LOOP", "ENDLOOP");
2216}
2217
d0313fb7 2218/* Normally, endloop gets eaten by the preceding loop. */
9a736b6b 2219
39bec121 2220static void
f1e7a2c9
NC
2221tic54x_endloop (ignore)
2222 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
2223{
2224 as_bad (_("ENDLOOP without corresponding LOOP"));
2225 ignore_rest_of_line ();
2226}
2227
d0313fb7 2228/* .break [condition]. */
9a736b6b 2229
39bec121 2230static void
f1e7a2c9
NC
2231tic54x_break (ignore)
2232 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
2233{
2234 int cond = 1;
2235
2236 ILLEGAL_WITHIN_STRUCT ();
2237
2238 SKIP_WHITESPACE ();
1aea3bb8 2239 if (!is_end_of_line[(int) *input_line_pointer])
9a736b6b
NC
2240 cond = get_absolute_expression ();
2241
39bec121 2242 if (cond)
9a736b6b 2243 end_repeat (substitution_line ? 1 : 0);
39bec121
TW
2244}
2245
2246static void
f1e7a2c9
NC
2247set_address_mode (mode)
2248 int mode;
39bec121
TW
2249{
2250 amode = mode;
2251 if (mode == far_mode)
2252 {
1aea3bb8 2253 symbolS *symbolP = symbol_new ("__allow_far", absolute_section,
9a736b6b 2254 (valueT) 1, &zero_address_frag);
39bec121
TW
2255 SF_SET_LOCAL (symbolP);
2256 symbol_table_insert (symbolP);
2257 }
2258}
2259
2260static int address_mode_needs_set = 1;
f1e7a2c9 2261
39bec121 2262static void
f1e7a2c9
NC
2263tic54x_address_mode (mode)
2264 int mode;
39bec121 2265{
1aea3bb8 2266 if (assembly_begun && amode != (unsigned) mode)
39bec121
TW
2267 {
2268 as_bad (_("Mixing of normal and extended addressing not supported"));
2269 ignore_rest_of_line ();
2270 return;
2271 }
2272 if (mode == far_mode && cpu != VNONE && cpu != V548 && cpu != V549)
2273 {
2274 as_bad (_("Extended addressing not supported on the specified CPU"));
2275 ignore_rest_of_line ();
2276 return;
2277 }
2278
2279 set_address_mode (mode);
2280 demand_empty_rest_of_line ();
2281}
2282
2283/* .sblock "section"|section [,...,"section"|section]
9a736b6b
NC
2284 Designate initialized sections for blocking. */
2285
39bec121 2286static void
f1e7a2c9
NC
2287tic54x_sblock (ignore)
2288 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
2289{
2290 int c = ',';
2291
2292 ILLEGAL_WITHIN_STRUCT ();
2293
2294 while (c == ',')
2295 {
2296 segT seg;
2297 char *name;
1aea3bb8 2298
39bec121 2299 if (*input_line_pointer == '"')
9a736b6b
NC
2300 {
2301 int len;
f1e7a2c9 2302
9a736b6b
NC
2303 name = demand_copy_C_string (&len);
2304 }
39bec121 2305 else
9a736b6b
NC
2306 {
2307 char *section_name = input_line_pointer;
f1e7a2c9 2308
9a736b6b
NC
2309 c = get_symbol_end ();
2310 name = xmalloc (strlen (section_name) + 1);
2311 strcpy (name, section_name);
2312 *input_line_pointer = c;
2313 }
39bec121
TW
2314
2315 seg = bfd_get_section_by_name (stdoutput, name);
2316 if (seg == NULL)
9a736b6b
NC
2317 {
2318 as_bad (_("Unrecognized section '%s'"), name);
2319 ignore_rest_of_line ();
2320 return;
2321 }
39bec121 2322 else if (!tic54x_initialized_section (seg))
9a736b6b
NC
2323 {
2324 as_bad (_(".sblock may be used for initialized sections only"));
2325 ignore_rest_of_line ();
2326 return;
2327 }
39bec121
TW
2328 seg->flags |= SEC_BLOCK;
2329
2330 c = *input_line_pointer;
1aea3bb8 2331 if (!is_end_of_line[(int) c])
9a736b6b 2332 ++input_line_pointer;
39bec121
TW
2333 }
2334
2335 demand_empty_rest_of_line ();
2336}
2337
2338/* symbol .set value
1aea3bb8 2339 symbol .equ value
39bec121
TW
2340
2341 value must be defined externals; no forward-referencing allowed
d0313fb7 2342 symbols assigned with .set/.equ may not be redefined. */
9a736b6b 2343
39bec121 2344static void
f1e7a2c9
NC
2345tic54x_set (ignore)
2346 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
2347{
2348 symbolS *symbolP;
2349 char *name;
2350
2351 ILLEGAL_WITHIN_STRUCT ();
2352
2353 if (!line_label)
2354 {
2355 as_bad (_("Symbol missing for .set/.equ"));
2356 ignore_rest_of_line ();
2357 return;
2358 }
2359 name = xstrdup (S_GET_NAME (line_label));
2360 line_label = NULL;
2361 if ((symbolP = symbol_find (name)) == NULL
2362 && (symbolP = md_undefined_symbol (name)) == NULL)
2363 {
2364 symbolP = symbol_new (name, absolute_section, 0, &zero_address_frag);
2365 S_SET_STORAGE_CLASS (symbolP, C_STAT);
2366 }
2367 free (name);
2368 S_SET_DATA_TYPE (symbolP, T_INT);
2369 S_SET_SEGMENT (symbolP, absolute_section);
2370 symbol_table_insert (symbolP);
2371 pseudo_set (symbolP);
2372 demand_empty_rest_of_line ();
2373}
2374
2375/* .fclist
2376 .fcnolist
9a736b6b
NC
2377 List false conditional blocks. */
2378
39bec121 2379static void
f1e7a2c9
NC
2380tic54x_fclist (show)
2381 int show;
39bec121
TW
2382{
2383 if (show)
2384 listing &= ~LISTING_NOCOND;
2385 else
2386 listing |= LISTING_NOCOND;
2387 demand_empty_rest_of_line ();
2388}
2389
2390static void
f1e7a2c9
NC
2391tic54x_sslist (show)
2392 int show;
39bec121
TW
2393{
2394 ILLEGAL_WITHIN_STRUCT ();
2395
2396 listing_sslist = show;
2397}
2398
1aea3bb8 2399/* .var SYM[,...,SYMN]
9a736b6b
NC
2400 Define a substitution string to be local to a macro. */
2401
39bec121 2402static void
f1e7a2c9
NC
2403tic54x_var (ignore)
2404 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
2405{
2406 static char empty[] = "";
2407 char *name;
2408 int c;
2409
2410 ILLEGAL_WITHIN_STRUCT ();
2411
2412 if (macro_level == 0)
2413 {
2414 as_bad (_(".var may only be used within a macro definition"));
2415 ignore_rest_of_line ();
2416 return;
2417 }
1aea3bb8 2418 do
39bec121 2419 {
3882b010 2420 if (!ISALPHA (*input_line_pointer))
9a736b6b
NC
2421 {
2422 as_bad (_("Substitution symbols must begin with a letter"));
2423 ignore_rest_of_line ();
2424 return;
2425 }
39bec121
TW
2426 name = input_line_pointer;
2427 c = get_symbol_end ();
9a736b6b 2428 /* .var symbols start out with a null string. */
1aea3bb8 2429 name = strcpy (xmalloc (strlen (name) + 1), name);
39bec121
TW
2430 hash_insert (subsym_hash[macro_level], name, empty);
2431 *input_line_pointer = c;
2432 if (c == ',')
9a736b6b
NC
2433 {
2434 ++input_line_pointer;
2435 if (is_end_of_line[(int) *input_line_pointer])
2436 c = *input_line_pointer;
2437 }
39bec121
TW
2438 }
2439 while (c == ',');
2440
2441 demand_empty_rest_of_line ();
2442}
2443
1aea3bb8 2444/* .mlib <macro library filename>
39bec121
TW
2445
2446 Macro libraries are archived (standard AR-format) text macro definitions
2447 Expand the file and include it.
2448
d0313fb7 2449 FIXME need to try the source file directory as well. */
9a736b6b 2450
39bec121 2451static void
f1e7a2c9
NC
2452tic54x_mlib (ignore)
2453 int ignore ATTRIBUTE_UNUSED;
39bec121
TW
2454{
2455 char *filename;
2456 char *path;
2457 int len, i;
2458 bfd *abfd, *mbfd;
2459
2460 ILLEGAL_WITHIN_STRUCT ();
2461
9a736b6b 2462 /* Parse the filename. */
39bec121
TW
2463 if (*input_line_pointer == '"')
2464 {
2465 if ((filename = demand_copy_C_string (&len)) == NULL)
9a736b6b 2466 return;
39bec121
TW
2467 }
2468 else
2469 {
2470 SKIP_WHITESPACE ();
2471 len = 0;
1aea3bb8 2472 while (!is_end_of_line[(int) *input_line_pointer]
3882b010 2473 && !ISSPACE (*input_line_pointer))
9a736b6b
NC
2474 {
2475 obstack_1grow (&notes, *input_line_pointer);
2476 ++input_line_pointer;
2477 ++len;
2478 }
39bec121
TW
2479 obstack_1grow (&notes, '\0');
2480 filename = obstack_finish (&notes);
2481 }
2482 demand_empty_rest_of_line ();
2483
2484 tic54x_set_default_include (0);
2485 path = xmalloc ((unsigned long) len + include_dir_maxlen + 5);
f1e7a2c9 2486
1aea3bb8 2487 for (i = 0; i < include_dir_count; i++)
39bec121
TW
2488 {
2489 FILE *try;
f1e7a2c9 2490
39bec121
TW
2491 strcpy (path, include_dirs[i]);
2492 strcat (path, "/");
2493 strcat (path, filename);
2494 if ((try = fopen (path, "r")) != NULL)
9a736b6b
NC
2495 {
2496 fclose (try);
2497 break;
2498 }
1aea3bb8 2499 }
f1e7a2c9 2500
39bec121
TW
2501 if (i >= include_dir_count)
2502 {
2503 free (path);
2504 path = filename;
2505 }
2506
2507 /* FIXME: if path is found, malloc'd storage is not freed. Of course, this
2508 happens all over the place, and since the assembler doesn't usually keep
9a736b6b 2509 running for a very long time, it really doesn't matter. */
39bec121
TW
2510 register_dependency (path);
2511
d0313fb7 2512 /* Expand all archive entries to temporary files and include them. */
39bec121
TW
2513 abfd = bfd_openr (path, NULL);
2514 if (!abfd)
2515 {
2516 as_bad (_("Can't open macro library file '%s' for reading."), path);
2517 as_perror ("%s", path);
2518 ignore_rest_of_line ();
2519 return;
2520 }
2521 if (!bfd_check_format (abfd, bfd_archive))
2522 {
2523 as_bad (_("File '%s' not in macro archive format"), path);
2524 ignore_rest_of_line ();
2525 return;
2526 }
2527
d0313fb7 2528 /* Open each BFD as binary (it should be straight ASCII text). */
39bec121
TW
2529 for (mbfd = bfd_openr_next_archived_file (abfd, NULL);
2530 mbfd != NULL; mbfd = bfd_openr_next_archived_file (abfd, mbfd))
2531 {
d0313fb7 2532 /* Get a size at least as big as the archive member. */
39bec121
TW
2533 bfd_size_type size = bfd_get_size (mbfd);
2534 char *buf = xmalloc (size);
2535 char *fname = tmpnam (NULL);
2536 FILE *ftmp;
2537
d0313fb7 2538 /* We're not sure how big it is, but it will be smaller than "size". */
0e1a166b 2539 bfd_bread (buf, size, mbfd);
39bec121 2540
1aea3bb8 2541 /* Write to a temporary file, then use s_include to include it
9a736b6b 2542 a bit of a hack. */
39bec121 2543 ftmp = fopen (fname, "w+b");
1aea3bb8
NC
2544 fwrite ((void *) buf, size, 1, ftmp);
2545 if (buf[size - 1] != '\n')
9a736b6b 2546 fwrite ("\n", 1, 1, ftmp);
39bec121
TW
2547 fclose (ftmp);
2548 free (buf);
2549 input_scrub_insert_file (fname);
2550 unlink (fname);
2551 }
2552}
2553
1aea3bb8 2554const pseudo_typeS md_pseudo_table[] =
39bec121 2555{
9a736b6b
NC
2556 { "algebraic", s_ignore , 0 },
2557 { "align" , tic54x_align_words , 128 },
6e917903
TW
2558 { "ascii" , tic54x_stringer , 'p' },
2559 { "asciz" , tic54x_stringer , 'P' },
9a736b6b
NC
2560 { "even" , tic54x_align_words , 2 },
2561 { "asg" , tic54x_asg , 0 },
2562 { "eval" , tic54x_eval , 0 },
2563 { "bss" , tic54x_bss , 0 },
2564 { "byte" , tic54x_cons , 'b' },
2565 { "ubyte" , tic54x_cons , 'B' },
2566 { "char" , tic54x_cons , 'c' },
2567 { "uchar" , tic54x_cons , 'C' },
2568 { "clink" , tic54x_clink , 0 },
2569 { "c_mode" , tic54x_address_mode , c_mode },
2570 { "copy" , tic54x_include , 'c' },
2571 { "include" , tic54x_include , 'i' },
2572 { "data" , tic54x_sect , 'd' },
2573 { "double" , tic54x_float_cons , 'd' },
2574 { "ldouble" , tic54x_float_cons , 'l' },
2575 { "drlist" , s_ignore , 0 },
2576 { "drnolist" , s_ignore , 0 },
2577 { "emsg" , tic54x_message , 'e' },
2578 { "mmsg" , tic54x_message , 'm' },
2579 { "wmsg" , tic54x_message , 'w' },
9a736b6b
NC
2580 { "far_mode" , tic54x_address_mode , far_mode },
2581 { "fclist" , tic54x_fclist , 1 },
2582 { "fcnolist" , tic54x_fclist , 0 },
2583 { "field" , tic54x_field , -1 },
2584 { "float" , tic54x_float_cons , 'f' },
2585 { "xfloat" , tic54x_float_cons , 'x' },
2586 { "global" , tic54x_global , 'g' },
2587 { "def" , tic54x_global , 'd' },
2588 { "ref" , tic54x_global , 'r' },
2589 { "half" , tic54x_cons , 'h' },
2590 { "uhalf" , tic54x_cons , 'H' },
2591 { "short" , tic54x_cons , 's' },
2592 { "ushort" , tic54x_cons , 'S' },
2593 { "if" , s_if , (int) O_ne },
2594 { "elseif" , s_elseif , (int) O_ne },
2595 { "else" , s_else , 0 },
2596 { "endif" , s_endif , 0 },
2597 { "int" , tic54x_cons , 'i' },
2598 { "uint" , tic54x_cons , 'I' },
2599 { "word" , tic54x_cons , 'w' },
2600 { "uword" , tic54x_cons , 'W' },
2601 { "label" , tic54x_label , 0 }, /* Loadtime
2602 address. */
2603 { "length" , s_ignore , 0 },
2604 { "width" , s_ignore , 0 },
9a736b6b
NC
2605 { "long" , tic54x_cons , 'l' },
2606 { "ulong" , tic54x_cons , 'L' },
2607 { "xlong" , tic54x_cons , 'x' },
2608 { "loop" , tic54x_loop , 1024 },
2609 { "break" , tic54x_break , 0 },
2610 { "endloop" , tic54x_endloop , 0 },
2611 { "mlib" , tic54x_mlib , 0 },
2612 { "mlist" , s_ignore , 0 },
2613 { "mnolist" , s_ignore , 0 },
2614 { "mmregs" , tic54x_mmregs , 0 },
2615 { "newblock" , tic54x_clear_local_labels, 0 },
2616 { "option" , s_ignore , 0 },
2617 { "p2align" , tic54x_p2align , 0 },
9a736b6b
NC
2618 { "sblock" , tic54x_sblock , 0 },
2619 { "sect" , tic54x_sect , '*' },
2620 { "set" , tic54x_set , 0 },
2621 { "equ" , tic54x_set , 0 },
2622 { "space" , tic54x_space , 0 },
2623 { "bes" , tic54x_space , 1 },
2624 { "sslist" , tic54x_sslist , 1 },
2625 { "ssnolist" , tic54x_sslist , 0 },
2626 { "string" , tic54x_stringer , 's' },
2627 { "pstring" , tic54x_stringer , 'p' },
2628 { "struct" , tic54x_struct , 0 },
2629 { "tag" , tic54x_tag , 0 },
2630 { "endstruct", tic54x_endstruct , 0 },
2631 { "tab" , s_ignore , 0 },
2632 { "text" , tic54x_sect , 't' },
9a736b6b
NC
2633 { "union" , tic54x_struct , 1 },
2634 { "endunion" , tic54x_endstruct , 1 },
2635 { "usect" , tic54x_usect , 0 },
2636 { "var" , tic54x_var , 0 },
2637 { "version" , tic54x_version , 0 },
2638 {0 , 0 , 0 }
39bec121
TW
2639};
2640
39bec121
TW
2641int
2642md_parse_option (c, arg)
1aea3bb8
NC
2643 int c;
2644 char *arg;
39bec121
TW
2645{
2646 switch (c)
2647 {
2648 default:
2649 return 0;
2650 case OPTION_COFF_VERSION:
2651 {
9a736b6b 2652 int version = atoi (arg);
f1e7a2c9 2653
9a736b6b
NC
2654 if (version != 0 && version != 1 && version != 2)
2655 as_fatal (_("Bad COFF version '%s'"), arg);
2656 /* FIXME -- not yet implemented. */
2657 break;
39bec121
TW
2658 }
2659 case OPTION_CPU_VERSION:
2660 {
9a736b6b
NC
2661 cpu = lookup_version (arg);
2662 cpu_needs_set = 1;
2663 if (cpu == VNONE)
2664 as_fatal (_("Bad CPU version '%s'"), arg);
2665 break;
39bec121
TW
2666 }
2667 case OPTION_ADDRESS_MODE:
2668 amode = far_mode;
2669 address_mode_needs_set = 1;
2670 break;
2671 case OPTION_STDERR_TO_FILE:
2672 {
9a736b6b
NC
2673 char *filename = arg;
2674 FILE *fp = fopen (filename, "w+");
f1e7a2c9 2675
9a736b6b
NC
2676 if (fp == NULL)
2677 as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
2678 fclose (fp);
2679 if ((fp = freopen (filename, "w+", stderr)) == NULL)
2680 as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
2681 break;
39bec121
TW
2682 }
2683 }
2684
2685 return 1;
2686}
2687
1aea3bb8 2688/* Create a "local" substitution string hash table for a new macro level
39bec121
TW
2689 Some docs imply that macros have to use .newblock in order to be able
2690 to re-use a local label. We effectively do an automatic .newblock by
d0313fb7 2691 deleting the local label hash between macro invocations. */
9a736b6b 2692
1aea3bb8 2693void
39bec121
TW
2694tic54x_macro_start ()
2695{
2696 ++macro_level;
2697 subsym_hash[macro_level] = hash_new ();
2698 local_label_hash[macro_level] = hash_new ();
2699}
2700
2701void
d0313fb7
NC
2702tic54x_macro_info (info)
2703 void *info;
39bec121
TW
2704{
2705 struct formal_struct
2706 {
9a736b6b
NC
2707 struct formal_struct *next; /* Next formal in list */
2708 sb name; /* Name of the formal */
2709 sb def; /* The default value */
2710 sb actual; /* The actual argument (changed on
2711 each expansion) */
2712 int index; /* The index of the formal
2713 0 .. formal_count - 1 */
39bec121
TW
2714 } *entry;
2715 struct macro_struct
2716 {
9a736b6b
NC
2717 sb sub; /* Substitution text. */
2718 int formal_count; /* Number of formal args. */
2719 struct formal_struct *formals; /* Pointer to list of
2720 formal_structs. */
2721 struct hash_control *formal_hash; /* Hash table of formals. */
39bec121
TW
2722 } *macro;
2723
1aea3bb8 2724 macro = (struct macro_struct *) info;
39bec121 2725
d0313fb7 2726 /* Put the formal args into the substitution symbol table. */
39bec121
TW
2727 for (entry = macro->formals; entry; entry = entry->next)
2728 {
2729 char *name = strncpy (xmalloc (entry->name.len + 1),
9a736b6b 2730 entry->name.ptr, entry->name.len);
39bec121 2731 char *value = strncpy (xmalloc (entry->actual.len + 1),
9a736b6b 2732 entry->actual.ptr, entry->actual.len);
f1e7a2c9 2733
39bec121
TW
2734 name[entry->name.len] = '\0';
2735 value[entry->actual.len] = '\0';
2736 hash_insert (subsym_hash[macro_level], name, value);
2737 }
2738}
2739
d0313fb7 2740/* Get rid of this macro's .var's, arguments, and local labels. */
9a736b6b 2741
39bec121
TW
2742void
2743tic54x_macro_end ()
2744{
2745 hash_die (subsym_hash[macro_level]);
2746 subsym_hash[macro_level] = NULL;
2747 hash_die (local_label_hash[macro_level]);
2748 local_label_hash[macro_level] = NULL;
2749 --macro_level;
2750}
2751
2752static int
f1e7a2c9
NC
2753subsym_symlen (a, ignore)
2754 char *a;
2755 char *ignore ATTRIBUTE_UNUSED;
39bec121
TW
2756{
2757 return strlen (a);
2758}
2759
d0313fb7 2760/* Compare symbol A to string B. */
9a736b6b 2761
39bec121 2762static int
f1e7a2c9
NC
2763subsym_symcmp (a, b)
2764 char *a;
2765 char *b;
39bec121
TW
2766{
2767 return strcmp (a, b);
2768}
2769
33b7f697 2770/* Return the index of the first occurrence of B in A, or zero if none
d0313fb7 2771 assumes b is an integer char value as a string. Index is one-based. */
9a736b6b 2772
39bec121 2773static int
f1e7a2c9
NC
2774subsym_firstch (a, b)
2775 char *a;
2776 char *b;
39bec121
TW
2777{
2778 int val = atoi (b);
2779 char *tmp = strchr (a, val);
1aea3bb8 2780
39bec121
TW
2781 return tmp ? tmp - a + 1 : 0;
2782}
2783
d0313fb7 2784/* Similar to firstch, but returns index of last occurrence of B in A. */
9a736b6b 2785
39bec121 2786static int
f1e7a2c9
NC
2787subsym_lastch (a, b)
2788 char *a;
2789 char *b;
39bec121
TW
2790{
2791 int val = atoi (b);
2792 char *tmp = strrchr (a, val);
2793
2794 return tmp ? tmp - a + 1 : 0;
2795}
2796
d0313fb7 2797/* Returns 1 if string A is defined in the symbol table (NOT the substitution
9a736b6b
NC
2798 symbol table). */
2799
39bec121 2800static int
f1e7a2c9
NC
2801subsym_isdefed (a, ignore)
2802 char *a;
2803 char *ignore ATTRIBUTE_UNUSED;
39bec121
TW
2804{
2805 symbolS *symbolP = symbol_find (a);
2806
2807 return symbolP != NULL;
2808}
2809
d0313fb7 2810/* Assign first member of comma-separated list B (e.g. "1,2,3") to the symbol
39bec121 2811 A, or zero if B is a null string. Both arguments *must* be substitution
d0313fb7 2812 symbols, unsubstituted. */
9a736b6b 2813
39bec121 2814static int
f1e7a2c9
NC
2815subsym_ismember (sym, list)
2816 char *sym;
2817 char *list;
39bec121
TW
2818{
2819 char *elem, *ptr, *listv;
2820
2821 if (!list)
2822 return 0;
2823
2824 listv = subsym_lookup (list, macro_level);
2825 if (!listv)
2826 {
2827 as_bad (_("Undefined substitution symbol '%s'"), list);
2828 ignore_rest_of_line ();
2829 return 0;
2830 }
2831
1aea3bb8 2832 ptr = elem = xmalloc (strlen (listv) + 1);
39bec121
TW
2833 strcpy (elem, listv);
2834 while (*ptr && *ptr != ',')
2835 ++ptr;
2836 *ptr++ = 0;
2837
d0313fb7 2838 subsym_create_or_replace (sym, elem);
39bec121 2839
d0313fb7 2840 /* Reassign the list. */
39bec121 2841 subsym_create_or_replace (list, ptr);
1aea3bb8 2842
d0313fb7 2843 /* Assume this value, docs aren't clear. */
39bec121
TW
2844 return *list != 0;
2845}
2846
d0313fb7 2847/* Return zero if not a constant; otherwise:
39bec121
TW
2848 1 if binary
2849 2 if octal
2850 3 if hexadecimal
2851 4 if character
d0313fb7 2852 5 if decimal. */
9a736b6b 2853
39bec121 2854static int
f1e7a2c9
NC
2855subsym_iscons (a, ignore)
2856 char *a;
2857 char *ignore ATTRIBUTE_UNUSED;
39bec121
TW
2858{
2859 expressionS exp;
2860
2861 parse_expression (a, &exp);
2862
2863 if (exp.X_op == O_constant)
2864 {
2865 int len = strlen (a);
2866
3882b010 2867 switch (TOUPPER (a[len - 1]))
9a736b6b
NC
2868 {
2869 case 'B':
2870 return 1;
2871 case 'Q':
2872 return 2;
2873 case 'H':
2874 return 3;
2875 case '\'':
2876 return 4;
2877 default:
2878 break;
2879 }
d0313fb7 2880 /* No suffix; either octal, hex, or decimal. */
39bec121 2881 if (*a == '0' && len > 1)
9a736b6b 2882 {
3882b010 2883 if (TOUPPER (a[1]) == 'X')
9a736b6b
NC
2884 return 3;
2885 return 2;
2886 }
39bec121
TW
2887 return 5;
2888 }
2889
2890 return 0;
2891}
2892
d0313fb7 2893/* Return 1 if A is a valid symbol name. Expects string input. */
9a736b6b 2894
39bec121 2895static int
f1e7a2c9
NC
2896subsym_isname (a, ignore)
2897 char *a;
2898 char *ignore ATTRIBUTE_UNUSED;
39bec121
TW
2899{
2900 if (!is_name_beginner (*a))
2901 return 0;
2902 while (*a)
2903 {
2904 if (!is_part_of_name (*a))
9a736b6b 2905 return 0;
39bec121
TW
2906 ++a;
2907 }
2908 return 1;
2909}
2910
d0313fb7 2911/* Return whether the string is a register; accepts ar0-7, unless .mmregs has
39bec121 2912 been seen; if so, recognize any memory-mapped register.
d0313fb7 2913 Note this does not recognize "A" or "B" accumulators. */
9a736b6b 2914
39bec121 2915static int
f1e7a2c9
NC
2916subsym_isreg (a, ignore)
2917 char *a;
2918 char *ignore ATTRIBUTE_UNUSED;
39bec121
TW
2919{
2920 if (hash_find (reg_hash, a))
2921 return 1;
2922 if (hash_find (mmreg_hash, a))
2923 return 1;
2924 return 0;
2925}
2926
33b7f697 2927/* Return the structure size, given the stag. */
9a736b6b 2928
39bec121 2929static int
f1e7a2c9
NC
2930subsym_structsz (name, ignore)
2931 char *name;
2932 char *ignore ATTRIBUTE_UNUSED;
39bec121 2933{
1aea3bb8 2934 struct stag *stag = (struct stag *) hash_find (stag_hash, name);
f1e7a2c9 2935
39bec121
TW
2936 if (stag)
2937 return stag->size;
2938
2939 return 0;
2940}
2941
2942/* If anybody actually uses this, they can fix it :)
2943 FIXME I'm not sure what the "reference point" of a structure is. It might
2944 be either the initial offset given .struct, or it may be the offset of the
2945 structure within another structure, or it might be something else
2946 altogether. since the TI assembler doesn't seem to ever do anything but
d0313fb7 2947 return zero, we punt and return zero. */
9a736b6b 2948
39bec121 2949static int
f1e7a2c9
NC
2950subsym_structacc (stag_name, ignore)
2951 char *stag_name ATTRIBUTE_UNUSED;
2952 char *ignore ATTRIBUTE_UNUSED;
39bec121
TW
2953{
2954 return 0;
2955}
2956
2957static float
2958math_ceil (arg1, ignore)
1aea3bb8
NC
2959 float arg1;
2960 float ignore ATTRIBUTE_UNUSED;
39bec121 2961{
1aea3bb8 2962 return (float) ceil (arg1);
39bec121 2963}
d0313fb7 2964
39bec121
TW
2965static float
2966math_cvi (arg1, ignore)
1aea3bb8
NC
2967 float arg1;
2968 float ignore ATTRIBUTE_UNUSED;
39bec121 2969{
1aea3bb8 2970 return (int) arg1;
39bec121 2971}
d0313fb7 2972
39bec121
TW
2973static float
2974math_floor (arg1, ignore)
1aea3bb8
NC
2975 float arg1;
2976 float ignore ATTRIBUTE_UNUSED;
39bec121 2977{
1aea3bb8 2978 return (float) floor (arg1);
39bec121 2979}
d0313fb7 2980
39bec121 2981static float
f1e7a2c9
NC
2982math_fmod (arg1, arg2)
2983 float arg1;
2984 float arg2;
39bec121 2985{
1aea3bb8 2986 return (int) arg1 % (int) arg2;
39bec121 2987}
d0313fb7 2988
39bec121
TW
2989static float
2990math_int (arg1, ignore)
1aea3bb8
NC
2991 float arg1;
2992 float ignore ATTRIBUTE_UNUSED;
39bec121 2993{
1aea3bb8 2994 return ((float) ((int) arg1)) == arg1;
39bec121 2995}
d0313fb7 2996
39bec121
TW
2997static float
2998math_round (arg1, ignore)
1aea3bb8
NC
2999 float arg1;
3000 float ignore ATTRIBUTE_UNUSED;
39bec121 3001{
1aea3bb8 3002 return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5);
39bec121 3003}
d0313fb7 3004
39bec121
TW
3005static float
3006math_sgn (arg1, ignore)
1aea3bb8
NC
3007 float arg1;
3008 float ignore ATTRIBUTE_UNUSED;
39bec121
TW
3009{
3010 return (arg1 < 0) ? -1 : (arg1 ? 1 : 0);
3011}
d0313fb7 3012
39bec121
TW
3013static float
3014math_trunc (arg1, ignore)
1aea3bb8
NC
3015 float arg1;
3016 float ignore ATTRIBUTE_UNUSED;
39bec121 3017{
1aea3bb8 3018 return (int) arg1;
39bec121
TW
3019}
3020
3021static float
3022math_acos (arg1, ignore)
1aea3bb8
NC
3023 float arg1;
3024 float ignore ATTRIBUTE_UNUSED;
39bec121 3025{
1aea3bb8 3026 return (float) acos (arg1);
39bec121 3027}
d0313fb7 3028
39bec121
TW
3029static float
3030math_asin (arg1, ignore)
1aea3bb8
NC
3031 float arg1;
3032 float ignore ATTRIBUTE_UNUSED;
39bec121 3033{
1aea3bb8 3034 return (float) asin (arg1);
39bec121 3035}
d0313fb7 3036
39bec121
TW
3037static float
3038math_atan (arg1, ignore)
1aea3bb8
NC
3039 float arg1;
3040 float ignore ATTRIBUTE_UNUSED;
39bec121 3041{
1aea3bb8 3042 return (float) atan (arg1);
39bec121 3043}
d0313fb7 3044
39bec121 3045static float
f1e7a2c9
NC
3046math_atan2 (arg1, arg2)
3047 float arg1;
3048 float arg2;
39bec121 3049{
1aea3bb8 3050 return (float) atan2 (arg1, arg2);
39bec121 3051}
d0313fb7 3052
39bec121
TW
3053static float
3054math_cosh (arg1, ignore)
1aea3bb8
NC
3055 float arg1;
3056 float ignore ATTRIBUTE_UNUSED;
39bec121 3057{
1aea3bb8 3058 return (float) cosh (arg1);
39bec121 3059}
d0313fb7 3060
39bec121
TW
3061static float
3062math_cos (arg1, ignore)
1aea3bb8
NC
3063 float arg1;
3064 float ignore ATTRIBUTE_UNUSED;
39bec121 3065{
1aea3bb8 3066 return (float) cos (arg1);
39bec121 3067}
d0313fb7 3068
39bec121
TW
3069static float
3070math_cvf (arg1, ignore)
1aea3bb8
NC
3071 float arg1;
3072 float ignore ATTRIBUTE_UNUSED;
39bec121 3073{
1aea3bb8 3074 return (float) arg1;
39bec121 3075}
d0313fb7 3076
39bec121
TW
3077static float
3078math_exp (arg1, ignore)
1aea3bb8
NC
3079 float arg1;
3080 float ignore ATTRIBUTE_UNUSED;
39bec121 3081{
1aea3bb8 3082 return (float) exp (arg1);
39bec121 3083}
d0313fb7 3084
39bec121
TW
3085static float
3086math_fabs (arg1, ignore)
1aea3bb8
NC
3087 float arg1;
3088 float ignore ATTRIBUTE_UNUSED;
39bec121 3089{
1aea3bb8 3090 return (float) fabs (arg1);
39bec121 3091}
d0313fb7
NC
3092
3093/* expr1 * 2^expr2. */
9a736b6b 3094
39bec121 3095static float
f1e7a2c9
NC
3096math_ldexp (arg1, arg2)
3097 float arg1;
3098 float arg2;
39bec121 3099{
1aea3bb8 3100 return arg1 * (float) pow (2.0, arg2);
39bec121 3101}
d0313fb7 3102
39bec121
TW
3103static float
3104math_log10 (arg1, ignore)
1aea3bb8
NC
3105 float arg1;
3106 float ignore ATTRIBUTE_UNUSED;
39bec121 3107{
1aea3bb8 3108 return (float) log10 (arg1);
39bec121 3109}
d0313fb7 3110
39bec121
TW
3111static float
3112math_log (arg1, ignore)
1aea3bb8
NC
3113 float arg1;
3114 float ignore ATTRIBUTE_UNUSED;
39bec121 3115{
1aea3bb8 3116 return (float) log (arg1);
39bec121 3117}
d0313fb7 3118
39bec121 3119static float
f1e7a2c9
NC
3120math_max (arg1, arg2)
3121 float arg1;
3122 float arg2;
39bec121
TW
3123{
3124 return (arg1 > arg2) ? arg1 : arg2;
3125}
d0313fb7 3126
39bec121 3127static float
f1e7a2c9
NC
3128math_min (arg1, arg2)
3129 float arg1;
3130 float arg2;
39bec121
TW
3131{
3132 return (arg1 < arg2) ? arg1 : arg2;
3133}
d0313fb7 3134
39bec121 3135static float
f1e7a2c9
NC
3136math_pow (arg1, arg2)
3137 float arg1;
3138 float arg2;
39bec121 3139{
1aea3bb8 3140 return (float) pow (arg1, arg2);
39bec121 3141}
d0313fb7 3142
39bec121
TW
3143static float
3144math_sin (arg1, ignore)
1aea3bb8
NC
3145 float arg1;
3146 float ignore ATTRIBUTE_UNUSED;
39bec121 3147{
1aea3bb8 3148 return (float) sin (arg1);
39bec121 3149}
d0313fb7 3150
39bec121
TW
3151static float
3152math_sinh (arg1, ignore)
1aea3bb8
NC
3153 float arg1;
3154 float ignore ATTRIBUTE_UNUSED;
39bec121 3155{
1aea3bb8 3156 return (float) sinh (arg1);
39bec121 3157}
d0313fb7 3158
39bec121
TW
3159static float
3160math_sqrt (arg1, ignore)
1aea3bb8
NC
3161 float arg1;
3162 float ignore ATTRIBUTE_UNUSED;
39bec121 3163{
1aea3bb8 3164 return (float) sqrt (arg1);
39bec121 3165}
d0313fb7 3166
39bec121
TW
3167static float
3168math_tan (arg1, ignore)
1aea3bb8
NC
3169 float arg1;
3170 float ignore ATTRIBUTE_UNUSED;
39bec121 3171{
1aea3bb8 3172 return (float) tan (arg1);
39bec121 3173}
d0313fb7 3174
39bec121
TW
3175static float
3176math_tanh (arg1, ignore)
1aea3bb8
NC
3177 float arg1;
3178 float ignore ATTRIBUTE_UNUSED;
39bec121 3179{
1aea3bb8 3180 return (float) tanh (arg1);
39bec121
TW
3181}
3182
d0313fb7 3183/* Built-in substitution symbol functions and math functions. */
1aea3bb8 3184typedef struct
39bec121
TW
3185{
3186 char *name;
f1e7a2c9 3187 int (*proc) PARAMS ((char *, char *));
39bec121
TW
3188 int nargs;
3189} subsym_proc_entry;
3190
d0313fb7
NC
3191static const subsym_proc_entry subsym_procs[] =
3192{
3193 /* Assembler built-in string substitution functions. */
39bec121
TW
3194 { "$symlen", subsym_symlen, 1, },
3195 { "$symcmp", subsym_symcmp, 2, },
3196 { "$firstch", subsym_firstch, 2, },
3197 { "$lastch", subsym_lastch, 2, },
3198 { "$isdefed", subsym_isdefed, 1, },
3199 { "$ismember", subsym_ismember, 2, },
3200 { "$iscons", subsym_iscons, 1, },
3201 { "$isname", subsym_isname, 1, },
3202 { "$isreg", subsym_isreg, 1, },
3203 { "$structsz", subsym_structsz, 1, },
3204 { "$structacc", subsym_structacc, 1, },
3205 { NULL, NULL, 0 },
3206};
3207
3208typedef struct
3209{
3210 char *name;
f1e7a2c9 3211 float (*proc) PARAMS ((float, float));
39bec121
TW
3212 int nargs;
3213 int int_return;
3214} math_proc_entry;
3215
d0313fb7
NC
3216static const math_proc_entry math_procs[] =
3217{
3218 /* Integer-returning built-in math functions. */
39bec121
TW
3219 { "$cvi", math_cvi, 1, 1 },
3220 { "$int", math_int, 1, 1 },
3221 { "$sgn", math_sgn, 1, 1 },
3222
d0313fb7 3223 /* Float-returning built-in math functions. */
39bec121
TW
3224 { "$acos", math_acos, 1, 0 },
3225 { "$asin", math_asin, 1, 0 },
3226 { "$atan", math_atan, 1, 0 },
1aea3bb8 3227 { "$atan2", math_atan2, 2, 0 },
39bec121
TW
3228 { "$ceil", math_ceil, 1, 0 },
3229 { "$cosh", math_cosh, 1, 0 },
3230 { "$cos", math_cos, 1, 0 },
3231 { "$cvf", math_cvf, 1, 0 },
3232 { "$exp", math_exp, 1, 0 },
3233 { "$fabs", math_fabs, 1, 0 },
3234 { "$floor", math_floor, 1, 0 },
3235 { "$fmod", math_fmod, 2, 0 },
3236 { "$ldexp", math_ldexp, 2, 0 },
3237 { "$log10", math_log10, 1, 0 },
3238 { "$log", math_log, 1, 0 },
3239 { "$max", math_max, 2, 0 },
3240 { "$min", math_min, 2, 0 },
3241 { "$pow", math_pow, 2, 0 },
3242 { "$round", math_round, 1, 0 },
3243 { "$sin", math_sin, 1, 0 },
3244 { "$sinh", math_sinh, 1, 0 },
3245 { "$sqrt", math_sqrt, 1, 0 },
3246 { "$tan", math_tan, 1, 0 },
3247 { "$tanh", math_tanh, 1, 0 },
3248 { "$trunc", math_trunc, 1, 0 },
3249 { NULL, NULL, 0, 0 },
3250};
3251
3252void
3253md_begin ()
3254{
6e917903 3255 template *tm;
39bec121
TW
3256 symbol *sym;
3257 const subsym_proc_entry *subsym_proc;
3258 const math_proc_entry *math_proc;
3259 const char *hash_err;
3260 char **symname;
3261 char *TIC54X_DIR = getenv ("TIC54X_DIR");
3262 char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
3263
3264 local_label_id = 0;
3265
f1e7a2c9 3266 /* Look for A_DIR and add it to the include list. */
39bec121
TW
3267 if (A_DIR != NULL)
3268 {
3269 char *tmp = xstrdup (A_DIR);
f1e7a2c9 3270
1aea3bb8
NC
3271 do
3272 {
3273 char *next = strchr (tmp, ';');
f1e7a2c9 3274
1aea3bb8
NC
3275 if (next)
3276 *next++ = '\0';
3277 add_include_dir (tmp);
3278 tmp = next;
3279 }
3280 while (tmp != NULL);
39bec121
TW
3281 }
3282
3283 op_hash = hash_new ();
6e917903 3284 for (tm = (template *) tic54x_optab; tm->name; tm++)
39bec121 3285 {
6e917903 3286 if (hash_find (op_hash, tm->name))
9a736b6b 3287 continue;
6e917903 3288 hash_err = hash_insert (op_hash, tm->name, (char *) tm);
39bec121 3289 if (hash_err)
9a736b6b 3290 as_fatal ("Internal Error: Can't hash %s: %s",
6e917903 3291 tm->name, hash_err);
39bec121
TW
3292 }
3293 parop_hash = hash_new ();
5d6255fe 3294 for (tm = (template *) tic54x_paroptab; tm->name; tm++)
39bec121 3295 {
6e917903 3296 if (hash_find (parop_hash, tm->name))
9a736b6b 3297 continue;
6e917903 3298 hash_err = hash_insert (parop_hash, tm->name, (char *) tm);
39bec121 3299 if (hash_err)
9a736b6b 3300 as_fatal ("Internal Error: Can't hash %s: %s",
6e917903 3301 tm->name, hash_err);
39bec121
TW
3302 }
3303 reg_hash = hash_new ();
1aea3bb8 3304 for (sym = (symbol *) regs; sym->name; sym++)
39bec121 3305 {
d0313fb7 3306 /* Add basic registers to the symbol table. */
39bec121 3307 symbolS *symbolP = symbol_new (sym->name, absolute_section,
9a736b6b 3308 (valueT) sym->value, &zero_address_frag);
39bec121
TW
3309 SF_SET_LOCAL (symbolP);
3310 symbol_table_insert (symbolP);
1aea3bb8 3311 hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
39bec121 3312 }
1aea3bb8
NC
3313 for (sym = (symbol *) mmregs; sym->name; sym++)
3314 hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
39bec121 3315 mmreg_hash = hash_new ();
1aea3bb8 3316 for (sym = (symbol *) mmregs; sym->name; sym++)
f1e7a2c9
NC
3317 hash_err = hash_insert (mmreg_hash, sym->name, (char *) sym);
3318
39bec121 3319 cc_hash = hash_new ();
1aea3bb8 3320 for (sym = (symbol *) condition_codes; sym->name; sym++)
f1e7a2c9
NC
3321 hash_err = hash_insert (cc_hash, sym->name, (char *) sym);
3322
39bec121 3323 cc2_hash = hash_new ();
1aea3bb8 3324 for (sym = (symbol *) cc2_codes; sym->name; sym++)
f1e7a2c9
NC
3325 hash_err = hash_insert (cc2_hash, sym->name, (char *) sym);
3326
39bec121 3327 cc3_hash = hash_new ();
1aea3bb8 3328 for (sym = (symbol *) cc3_codes; sym->name; sym++)
f1e7a2c9
NC
3329 hash_err = hash_insert (cc3_hash, sym->name, (char *) sym);
3330
39bec121 3331 sbit_hash = hash_new ();
1aea3bb8 3332 for (sym = (symbol *) status_bits; sym->name; sym++)
f1e7a2c9
NC
3333 hash_err = hash_insert (sbit_hash, sym->name, (char *) sym);
3334
39bec121 3335 misc_symbol_hash = hash_new ();
1aea3bb8 3336 for (symname = (char **) misc_symbols; *symname; symname++)
f1e7a2c9
NC
3337 hash_err = hash_insert (misc_symbol_hash, *symname, *symname);
3338
d0313fb7
NC
3339 /* Only the base substitution table and local label table are initialized;
3340 the others (for local macro substitution) get instantiated as needed. */
39bec121
TW
3341 local_label_hash[0] = hash_new ();
3342 subsym_hash[0] = hash_new ();
3343 for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++)
f1e7a2c9
NC
3344 hash_err = hash_insert (subsym_hash[0], subsym_proc->name,
3345 (char *) subsym_proc);
3346
39bec121
TW
3347 math_hash = hash_new ();
3348 for (math_proc = math_procs; math_proc->name; math_proc++)
3349 {
d0313fb7 3350 /* Insert into the main subsym hash for recognition; insert into
9a736b6b 3351 the math hash to actually store information. */
39bec121 3352 hash_err = hash_insert (subsym_hash[0], math_proc->name,
9a736b6b 3353 (char *) math_proc);
39bec121 3354 hash_err = hash_insert (math_hash, math_proc->name,
9a736b6b 3355 (char *) math_proc);
39bec121
TW
3356 }
3357 subsym_recurse_hash = hash_new ();
3358 stag_hash = hash_new ();
3359}
3360
39bec121 3361static int
f1e7a2c9
NC
3362is_accumulator (operand)
3363 struct opstruct *operand;
39bec121 3364{
1aea3bb8 3365 return strcasecmp (operand->buf, "a") == 0
39bec121
TW
3366 || strcasecmp (operand->buf, "b") == 0;
3367}
3368
9a736b6b
NC
3369/* Return the number of operands found, or -1 on error, copying the
3370 operands into the given array and the accompanying expressions into
3371 the next array. */
3372
39bec121 3373static int
f1e7a2c9
NC
3374get_operands (operands, line)
3375 struct opstruct operands[];
3376 char *line;
39bec121
TW
3377{
3378 char *lptr = line;
3379 int numexp = 0;
3380 int expecting_operand = 0;
3381 int i;
3382
1aea3bb8 3383 while (numexp < MAX_OPERANDS && !is_end_of_line[(int) *lptr])
39bec121
TW
3384 {
3385 int paren_not_balanced = 0;
3386 char *op_start, *op_end;
f1e7a2c9 3387
3882b010 3388 while (*lptr && ISSPACE (*lptr))
9a736b6b 3389 ++lptr;
39bec121
TW
3390 op_start = lptr;
3391 while (paren_not_balanced || *lptr != ',')
9a736b6b
NC
3392 {
3393 if (*lptr == '\0')
3394 {
3395 if (paren_not_balanced)
3396 {
3397 as_bad ("Unbalanced parenthesis in operand %d", numexp);
3398 return -1;
3399 }
3400 else
3401 break;
3402 }
3403 if (*lptr == '(')
3404 ++paren_not_balanced;
3405 else if (*lptr == ')')
3406 --paren_not_balanced;
3407 ++lptr;
3408 }
39bec121
TW
3409 op_end = lptr;
3410 if (op_end != op_start)
9a736b6b
NC
3411 {
3412 int len = op_end - op_start;
f1e7a2c9 3413
9a736b6b
NC
3414 strncpy (operands[numexp].buf, op_start, len);
3415 operands[numexp].buf[len] = 0;
3416 /* Trim trailing spaces; while the preprocessor gets rid of most,
3417 there are weird usage patterns that can introduce them
3418 (i.e. using strings for macro args). */
3882b010 3419 while (len > 0 && ISSPACE (operands[numexp].buf[len - 1]))
9a736b6b
NC
3420 operands[numexp].buf[--len] = 0;
3421 lptr = op_end;
3422 ++numexp;
3423 }
1aea3bb8 3424 else
9a736b6b
NC
3425 {
3426 if (expecting_operand || *lptr == ',')
3427 {
3428 as_bad ("Expecting operand after ','");
3429 return -1;
3430 }
3431 }
39bec121 3432 if (*lptr == ',')
9a736b6b
NC
3433 {
3434 if (*++lptr == '\0')
3435 {
3436 as_bad ("Expecting operand after ','");
3437 return -1;
3438 }
3439 expecting_operand = 1;
3440 }
39bec121
TW
3441 }
3442
3882b010 3443 while (*lptr && ISSPACE (*lptr++))
39bec121 3444 ;
1aea3bb8 3445 if (!is_end_of_line[(int) *lptr])
39bec121
TW
3446 {
3447 as_bad ("Extra junk on line");
3448 return -1;
3449 }
3450
d0313fb7 3451 /* OK, now parse them into expressions. */
1aea3bb8 3452 for (i = 0; i < numexp; i++)
39bec121
TW
3453 {
3454 memset (&operands[i].exp, 0, sizeof (operands[i].exp));
3455 if (operands[i].buf[0] == '#')
9a736b6b
NC
3456 {
3457 /* Immediate. */
3458 parse_expression (operands[i].buf + 1, &operands[i].exp);
3459 }
39bec121 3460 else if (operands[i].buf[0] == '@')
9a736b6b
NC
3461 {
3462 /* Direct notation. */
3463 parse_expression (operands[i].buf + 1, &operands[i].exp);
3464 }
39bec121 3465 else if (operands[i].buf[0] == '*')
9a736b6b
NC
3466 {
3467 /* Indirect. */
3468 char *paren = strchr (operands[i].buf, '(');
f1e7a2c9 3469
9a736b6b
NC
3470 /* Allow immediate syntax in the inner expression. */
3471 if (paren && paren[1] == '#')
3472 *++paren = '(';
3473
3474 /* Pull out the lk expression or SP offset, if present. */
3475 if (paren != NULL)
3476 {
3477 int len = strlen (paren);
3478 char *end = paren + len;
3479 int c;
f1e7a2c9 3480
9a736b6b
NC
3481 while (end[-1] != ')')
3482 if (--end <= paren)
3483 {
3484 as_bad (_("Badly formed address expression"));
3485 return -1;
3486 }
3487 c = *end;
3488 *end = '\0';
3489 parse_expression (paren, &operands[i].exp);
3490 *end = c;
3491 }
3492 else
3493 operands[i].exp.X_op = O_absent;
3494 }
39bec121 3495 else
9a736b6b 3496 parse_expression (operands[i].buf, &operands[i].exp);
39bec121
TW
3497 }
3498
3499 return numexp;
3500}
3501
d0313fb7 3502/* Predicates for different operand types. */
9a736b6b 3503
39bec121 3504static int
f1e7a2c9
NC
3505is_immediate (operand)
3506 struct opstruct *operand;
39bec121 3507{
1aea3bb8 3508 return *operand->buf == '#';
39bec121
TW
3509}
3510
3511/* This is distinguished from immediate because some numbers must be constants
d0313fb7 3512 and must *not* have the '#' prefix. */
9a736b6b 3513
39bec121 3514static int
f1e7a2c9
NC
3515is_absolute (operand)
3516 struct opstruct *operand;
39bec121
TW
3517{
3518 return operand->exp.X_op == O_constant && !is_immediate (operand);
3519}
3520
d0313fb7 3521/* Is this an indirect operand? */
9a736b6b 3522
39bec121 3523static int
f1e7a2c9
NC
3524is_indirect (operand)
3525 struct opstruct *operand;
39bec121
TW
3526{
3527 return operand->buf[0] == '*';
3528}
3529
d0313fb7 3530/* Is this a valid dual-memory operand? */
9a736b6b 3531
39bec121 3532static int
f1e7a2c9
NC
3533is_dual (operand)
3534 struct opstruct *operand;
39bec121
TW
3535{
3536 if (is_indirect (operand) && strncasecmp (operand->buf, "*ar", 3) == 0)
3537 {
3538 char *tmp = operand->buf + 3;
3539 int arf;
3540 int valid_mod;
1aea3bb8 3541
39bec121 3542 arf = *tmp++ - '0';
d0313fb7 3543 /* Only allow *ARx, *ARx-, *ARx+, or *ARx+0%. */
39bec121 3544 valid_mod = *tmp == '\0' ||
9a736b6b
NC
3545 strcasecmp (tmp, "-") == 0 ||
3546 strcasecmp (tmp, "+") == 0 ||
3547 strcasecmp (tmp, "+0%") == 0;
39bec121
TW
3548 return arf >= 2 && arf <= 5 && valid_mod;
3549 }
3550 return 0;
3551}
3552
3553static int
f1e7a2c9
NC
3554is_mmreg (operand)
3555 struct opstruct *operand;
39bec121 3556{
9a736b6b
NC
3557 return (is_absolute (operand)
3558 || is_immediate (operand)
3559 || hash_find (mmreg_hash, operand->buf) != 0);
39bec121
TW
3560}
3561
3562static int
f1e7a2c9
NC
3563is_type (operand, type)
3564 struct opstruct *operand;
3565 enum optype type;
39bec121
TW
3566{
3567 switch (type)
3568 {
3569 case OP_None:
3570 return operand->buf[0] == 0;
3571 case OP_Xmem:
3572 case OP_Ymem:
3573 return is_dual (operand);
3574 case OP_Sind:
3575 return is_indirect (operand);
3576 case OP_xpmad_ms7:
d0313fb7 3577 /* This one *must* be immediate. */
39bec121
TW
3578 return is_immediate (operand);
3579 case OP_xpmad:
3580 case OP_pmad:
3581 case OP_PA:
3582 case OP_dmad:
3583 case OP_Lmem:
3584 case OP_MMR:
3585 return 1;
3586 case OP_Smem:
d0313fb7 3587 /* Address may be a numeric, indirect, or an expression. */
39bec121
TW
3588 return !is_immediate (operand);
3589 case OP_MMRY:
3590 case OP_MMRX:
3591 return is_mmreg (operand);
3592 case OP_SRC:
3593 case OP_SRC1:
3594 case OP_RND:
3595 case OP_DST:
3596 return is_accumulator (operand);
3597 case OP_B:
3882b010 3598 return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'B';
39bec121 3599 case OP_A:
3882b010 3600 return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'A';
39bec121 3601 case OP_ARX:
1aea3bb8 3602 return strncasecmp ("ar", operand->buf, 2) == 0
3882b010 3603 && ISDIGIT (operand->buf[2]);
39bec121
TW
3604 case OP_SBIT:
3605 return hash_find (sbit_hash, operand->buf) != 0 || is_absolute (operand);
3606 case OP_CC:
3607 return hash_find (cc_hash, operand->buf) != 0;
3608 case OP_CC2:
3609 return hash_find (cc2_hash, operand->buf) != 0;
3610 case OP_CC3:
1aea3bb8 3611 return hash_find (cc3_hash, operand->buf) != 0
9a736b6b 3612 || is_immediate (operand) || is_absolute (operand);
39bec121
TW
3613 case OP_16:
3614 return (is_immediate (operand) || is_absolute (operand))
9a736b6b 3615 && operand->exp.X_add_number == 16;
39bec121 3616 case OP_N:
d0313fb7 3617 /* Allow st0 or st1 instead of a numeric. */
39bec121 3618 return is_absolute (operand) || is_immediate (operand) ||
9a736b6b
NC
3619 strcasecmp ("st0", operand->buf) == 0 ||
3620 strcasecmp ("st1", operand->buf) == 0;
39bec121
TW
3621 case OP_12:
3622 case OP_123:
3623 return is_absolute (operand) || is_immediate (operand);
3624 case OP_SHFT:
3625 return (is_immediate (operand) || is_absolute (operand))
9a736b6b 3626 && operand->exp.X_add_number >= 0 && operand->exp.X_add_number < 16;
39bec121 3627 case OP_SHIFT:
d0313fb7 3628 /* Let this one catch out-of-range values. */
39bec121 3629 return (is_immediate (operand) || is_absolute (operand))
9a736b6b 3630 && operand->exp.X_add_number != 16;
39bec121
TW
3631 case OP_BITC:
3632 case OP_031:
3633 case OP_k8:
3634 return is_absolute (operand) || is_immediate (operand);
3635 case OP_k8u:
1aea3bb8 3636 return is_immediate (operand)
9a736b6b
NC
3637 && operand->exp.X_op == O_constant
3638 && operand->exp.X_add_number >= 0
3639 && operand->exp.X_add_number < 256;
39bec121
TW
3640 case OP_lk:
3641 case OP_lku:
1aea3bb8 3642 /* Allow anything; assumes opcodes are ordered with Smem operands
9a736b6b 3643 versions first. */
39bec121
TW
3644 return 1;
3645 case OP_k5:
3646 case OP_k3:
3647 case OP_k9:
d0313fb7 3648 /* Just make sure it's an integer; check range later. */
39bec121
TW
3649 return is_immediate (operand);
3650 case OP_T:
1aea3bb8 3651 return strcasecmp ("t", operand->buf) == 0 ||
9a736b6b 3652 strcasecmp ("treg", operand->buf) == 0;
39bec121
TW
3653 case OP_TS:
3654 return strcasecmp ("ts", operand->buf) == 0;
3655 case OP_ASM:
3656 return strcasecmp ("asm", operand->buf) == 0;
3657 case OP_TRN:
3658 return strcasecmp ("trn", operand->buf) == 0;
3659 case OP_DP:
3660 return strcasecmp ("dp", operand->buf) == 0;
3661 case OP_ARP:
3662 return strcasecmp ("arp", operand->buf) == 0;
3663 default:
3664 return 0;
3665 }
3666}
3667
3668static int
3669operands_match (insn, operands, opcount, refoptype, minops, maxops)
1aea3bb8
NC
3670 tic54x_insn *insn;
3671 struct opstruct *operands;
3672 int opcount;
3673 const enum optype *refoptype;
f1e7a2c9
NC
3674 int minops;
3675 int maxops;
39bec121
TW
3676{
3677 int op = 0, refop = 0;
3678
3679 if (opcount == 0 && minops == 0)
f1e7a2c9 3680 return 1;
39bec121
TW
3681
3682 while (op <= maxops && refop <= maxops)
3683 {
3684 while (!is_type (&operands[op], OPTYPE (refoptype[refop])))
9a736b6b
NC
3685 {
3686 /* Skip an optional template operand if it doesn't agree
3687 with the current operand. */
3688 if (refoptype[refop] & OPT)
3689 {
3690 ++refop;
3691 --maxops;
3692 if (refop > maxops)
3693 return 0;
3694 }
3695 else
3696 return 0;
3697 }
39bec121 3698
d0313fb7 3699 /* Save the actual operand type for later use. */
39bec121
TW
3700 operands[op].type = OPTYPE (refoptype[refop]);
3701 ++refop;
3702 ++op;
d0313fb7 3703 /* Have we matched them all yet? */
39bec121 3704 if (op == opcount)
9a736b6b
NC
3705 {
3706 while (op < maxops)
3707 {
3708 /* If a later operand is *not* optional, no match. */
3709 if ((refoptype[refop] & OPT) == 0)
3710 return 0;
3711 /* Flag any implicit default OP_DST operands so we know to add
3712 them explicitly when encoding the operand later. */
3713 if (OPTYPE (refoptype[refop]) == OP_DST)
3714 insn->using_default_dst = 1;
3715 ++refop;
3716 ++op;
3717 }
3718
3719 return 1;
3720 }
39bec121
TW
3721 }
3722
3723 return 0;
3724}
3725
1aea3bb8 3726/* 16-bit direct memory address
39bec121
TW
3727 Explicit dmad operands are always in last word of insn (usually second
3728 word, but bumped to third if lk addressing is used)
3729
3730 We allow *(dmad) notation because the TI assembler allows it.
3731
1aea3bb8 3732 XPC_CODE:
39bec121
TW
3733 0 for 16-bit addresses
3734 1 for full 23-bit addresses
d0313fb7 3735 2 for the upper 7 bits of a 23-bit address (LDX). */
9a736b6b 3736
39bec121
TW
3737static int
3738encode_dmad (insn, operand, xpc_code)
1aea3bb8
NC
3739 tic54x_insn *insn;
3740 struct opstruct *operand;
3741 int xpc_code;
39bec121
TW
3742{
3743 int op = 1 + insn->is_lkaddr;
3744
d0313fb7 3745 /* Only allow *(dmad) expressions; all others are invalid. */
1aea3bb8 3746 if (is_indirect (operand) && operand->buf[strlen (operand->buf) - 1] != ')')
39bec121
TW
3747 {
3748 as_bad (_("Invalid dmad syntax '%s'"), operand->buf);
3749 return 0;
3750 }
3751
3752 insn->opcode[op].addr_expr = operand->exp;
3753
3754 if (insn->opcode[op].addr_expr.X_op == O_constant)
3755 {
3756 valueT value = insn->opcode[op].addr_expr.X_add_number;
f1e7a2c9 3757
39bec121 3758 if (xpc_code == 1)
9a736b6b
NC
3759 {
3760 insn->opcode[0].word &= 0xFF80;
3761 insn->opcode[0].word |= (value >> 16) & 0x7F;
3762 insn->opcode[1].word = value & 0xFFFF;
3763 }
39bec121 3764 else if (xpc_code == 2)
9a736b6b 3765 insn->opcode[op].word = (value >> 16) & 0xFFFF;
39bec121 3766 else
9a736b6b 3767 insn->opcode[op].word = value;
39bec121
TW
3768 }
3769 else
3770 {
d0313fb7 3771 /* Do the fixup later; just store the expression. */
39bec121
TW
3772 insn->opcode[op].word = 0;
3773 insn->opcode[op].r_nchars = 2;
3774
3775 if (amode == c_mode)
9a736b6b 3776 insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
39bec121 3777 else if (xpc_code == 1)
9a736b6b
NC
3778 {
3779 /* This relocation spans two words, so adjust accordingly. */
3780 insn->opcode[0].addr_expr = operand->exp;
3781 insn->opcode[0].r_type = BFD_RELOC_TIC54X_23;
3782 insn->opcode[0].r_nchars = 4;
3783 insn->opcode[0].unresolved = 1;
3784 /* It's really 2 words, but we want to stop encoding after the
3785 first, since we must encode both words at once. */
3786 insn->words = 1;
3787 }
39bec121 3788 else if (xpc_code == 2)
9a736b6b 3789 insn->opcode[op].r_type = BFD_RELOC_TIC54X_MS7_OF_23;
39bec121 3790 else
9a736b6b 3791 insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
39bec121
TW
3792
3793 insn->opcode[op].unresolved = 1;
3794 }
3795
3796 return 1;
3797}
3798
d0313fb7 3799/* 7-bit direct address encoding. */
9a736b6b 3800
39bec121
TW
3801static int
3802encode_address (insn, operand)
1aea3bb8
NC
3803 tic54x_insn *insn;
3804 struct opstruct *operand;
39bec121 3805{
d0313fb7 3806 /* Assumes that dma addresses are *always* in word 0 of the opcode. */
39bec121
TW
3807 insn->opcode[0].addr_expr = operand->exp;
3808
3809 if (operand->exp.X_op == O_constant)
3810 insn->opcode[0].word |= (operand->exp.X_add_number & 0x7F);
3811 else
3812 {
f1e7a2c9
NC
3813 if (operand->exp.X_op == O_register)
3814 as_bad (_("Use the .mmregs directive to use memory-mapped register names such as '%s'"), operand->buf);
d0313fb7 3815 /* Do the fixup later; just store the expression. */
39bec121
TW
3816 insn->opcode[0].r_nchars = 1;
3817 insn->opcode[0].r_type = BFD_RELOC_TIC54X_PARTLS7;
3818 insn->opcode[0].unresolved = 1;
3819 }
3820
3821 return 1;
3822}
3823
3824static int
f1e7a2c9
NC
3825encode_indirect (insn, operand)
3826 tic54x_insn *insn;
3827 struct opstruct *operand;
39bec121
TW
3828{
3829 int arf;
3830 int mod;
3831
3832 if (insn->is_lkaddr)
3833 {
d0313fb7 3834 /* lk addresses always go in the second insn word. */
3882b010 3835 mod = ((TOUPPER (operand->buf[1]) == 'A') ? 12 :
9a736b6b
NC
3836 (operand->buf[1] == '(') ? 15 :
3837 (strchr (operand->buf, '%') != NULL) ? 14 : 13);
39bec121 3838 arf = ((mod == 12) ? operand->buf[3] - '0' :
9a736b6b 3839 (mod == 15) ? 0 : operand->buf[4] - '0');
1aea3bb8 3840
39bec121
TW
3841 insn->opcode[1].addr_expr = operand->exp;
3842
3843 if (operand->exp.X_op == O_constant)
9a736b6b 3844 insn->opcode[1].word = operand->exp.X_add_number;
39bec121 3845 else
9a736b6b
NC
3846 {
3847 insn->opcode[1].word = 0;
3848 insn->opcode[1].r_nchars = 2;
3849 insn->opcode[1].r_type = BFD_RELOC_TIC54X_16_OF_23;
3850 insn->opcode[1].unresolved = 1;
3851 }
39bec121
TW
3852 }
3853 else if (strncasecmp (operand->buf, "*sp (", 4) == 0)
3854 {
d0313fb7 3855 /* Stack offsets look the same as 7-bit direct addressing. */
39bec121
TW
3856 return encode_address (insn, operand);
3857 }
3858 else
3859 {
3882b010 3860 arf = (TOUPPER (operand->buf[1]) == 'A' ?
9a736b6b 3861 operand->buf[3] : operand->buf[4]) - '0';
1aea3bb8
NC
3862
3863 if (operand->buf[1] == '+')
9a736b6b
NC
3864 {
3865 mod = 3; /* *+ARx */
3866 if (insn->tm->flags & FL_SMR)
3867 as_warn (_("Address mode *+ARx is write-only. "
3868 "Results of reading are undefined."));
3869 }
1aea3bb8 3870 else if (operand->buf[4] == '\0')
9a736b6b 3871 mod = 0; /* *ARx */
39bec121 3872 else if (operand->buf[5] == '\0')
9a736b6b 3873 mod = (operand->buf[4] == '-' ? 1 : 2); /* *ARx+ / *ARx- */
39bec121 3874 else if (operand->buf[6] == '\0')
9a736b6b
NC
3875 {
3876 if (operand->buf[5] == '0')
3877 mod = (operand->buf[4] == '-' ? 5 : 6); /* *ARx+0 / *ARx-0 */
3878 else
3879 mod = (operand->buf[4] == '-' ? 8 : 10);/* *ARx+% / *ARx-% */
3880 }
3882b010 3881 else if (TOUPPER (operand->buf[6]) == 'B')
9a736b6b 3882 mod = (operand->buf[4] == '-' ? 4 : 7); /* ARx+0B / *ARx-0B */
3882b010 3883 else if (TOUPPER (operand->buf[6]) == '%')
9a736b6b 3884 mod = (operand->buf[4] == '-' ? 9 : 11); /* ARx+0% / *ARx - 0% */
39bec121 3885 else
9a736b6b
NC
3886 {
3887 as_bad (_("Unrecognized indirect address format \"%s\""),
3888 operand->buf);
3889 return 0;
3890 }
1aea3bb8 3891 }
39bec121 3892
1aea3bb8 3893 insn->opcode[0].word |= 0x80 | (mod << 3) | arf;
39bec121
TW
3894
3895 return 1;
3896}
3897
3898static int
f1e7a2c9
NC
3899encode_integer (insn, operand, which, min, max, mask)
3900 tic54x_insn *insn;
3901 struct opstruct *operand;
3902 int which;
3903 int min;
3904 int max;
3905 unsigned short mask;
39bec121
TW
3906{
3907 long parse, integer;
3908
3909 insn->opcode[which].addr_expr = operand->exp;
3910
3911 if (operand->exp.X_op == O_constant)
3912 {
3913 parse = operand->exp.X_add_number;
d0313fb7 3914 /* Hack -- fixup for 16-bit hex quantities that get converted positive
9a736b6b 3915 instead of negative. */
39bec121 3916 if ((parse & 0x8000) && min == -32768 && max == 32767)
9a736b6b 3917 integer = (short) parse;
39bec121 3918 else
9a736b6b 3919 integer = parse;
39bec121
TW
3920
3921 if (integer >= min && integer <= max)
9a736b6b
NC
3922 {
3923 insn->opcode[which].word |= (integer & mask);
3924 return 1;
3925 }
1aea3bb8 3926 as_bad (_("Operand '%s' out of range (%d <= x <= %d)"),
9a736b6b 3927 operand->buf, min, max);
39bec121
TW
3928 }
3929 else
3930 {
3931 if (insn->opcode[which].addr_expr.X_op == O_constant)
9a736b6b
NC
3932 {
3933 insn->opcode[which].word |=
3934 insn->opcode[which].addr_expr.X_add_number & mask;
3935 }
39bec121 3936 else
9a736b6b
NC
3937 {
3938 /* Do the fixup later; just store the expression. */
3939 bfd_reloc_code_real_type rtype =
3940 (mask == 0x1FF ? BFD_RELOC_TIC54X_PARTMS9 :
3941 mask == 0xFFFF ? BFD_RELOC_TIC54X_16_OF_23 :
3942 mask == 0x7F ? BFD_RELOC_TIC54X_PARTLS7 : BFD_RELOC_8);
3943 int size = (mask == 0x1FF || mask == 0xFFFF) ? 2 : 1;
3944
3945 if (rtype == BFD_RELOC_8)
3946 as_bad (_("Error in relocation handling"));
3947
3948 insn->opcode[which].r_nchars = size;
3949 insn->opcode[which].r_type = rtype;
3950 insn->opcode[which].unresolved = 1;
3951 }
39bec121
TW
3952
3953 return 1;
3954 }
3955
3956 return 0;
3957}
3958
3959static int
f1e7a2c9
NC
3960encode_condition (insn, operand)
3961 tic54x_insn *insn;
3962 struct opstruct *operand;
39bec121 3963{
1aea3bb8 3964 symbol *cc = (symbol *) hash_find (cc_hash, operand->buf);
39bec121
TW
3965 if (!cc)
3966 {
3967 as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
3968 return 0;
3969 }
3970#define CC_GROUP 0x40
3971#define CC_ACC 0x08
3972#define CATG_A1 0x07
3973#define CATG_B1 0x30
3974#define CATG_A2 0x30
3975#define CATG_B2 0x0C
3976#define CATG_C2 0x03
d0313fb7 3977 /* Disallow group 1 conditions mixed with group 2 conditions
39bec121 3978 if group 1, allow only one category A and one category B
d0313fb7 3979 if group 2, allow only one each of category A, B, and C. */
39bec121
TW
3980 if (((insn->opcode[0].word & 0xFF) != 0))
3981 {
3982 if ((insn->opcode[0].word & CC_GROUP) != (cc->value & CC_GROUP))
9a736b6b
NC
3983 {
3984 as_bad (_("Condition \"%s\" does not match preceding group"),
3985 operand->buf);
3986 return 0;
3987 }
39bec121 3988 if (insn->opcode[0].word & CC_GROUP)
9a736b6b
NC
3989 {
3990 if ((insn->opcode[0].word & CC_ACC) != (cc->value & CC_ACC))
3991 {
3992 as_bad (_("Condition \"%s\" uses a different accumulator from "
3993 "a preceding condition"),
3994 operand->buf);
3995 return 0;
3996 }
3997 if ((insn->opcode[0].word & CATG_A1) && (cc->value & CATG_A1))
3998 {
3999 as_bad (_("Only one comparison conditional allowed"));
4000 return 0;
4001 }
4002 if ((insn->opcode[0].word & CATG_B1) && (cc->value & CATG_B1))
4003 {
4004 as_bad (_("Only one overflow conditional allowed"));
4005 return 0;
4006 }
4007 }
f1e7a2c9
NC
4008 else if ( ((insn->opcode[0].word & CATG_A2) && (cc->value & CATG_A2))
4009 || ((insn->opcode[0].word & CATG_B2) && (cc->value & CATG_B2))
4010 || ((insn->opcode[0].word & CATG_C2) && (cc->value & CATG_C2)))
9a736b6b
NC
4011 {
4012 as_bad (_("Duplicate %s conditional"), operand->buf);
4013 return 0;
4014 }
39bec121
TW
4015 }
4016
4017 insn->opcode[0].word |= cc->value;
4018 return 1;
4019}
4020
4021static int
f1e7a2c9
NC
4022encode_cc3 (insn, operand)
4023 tic54x_insn *insn;
4024 struct opstruct *operand;
39bec121 4025{
1aea3bb8 4026 symbol *cc3 = (symbol *) hash_find (cc3_hash, operand->buf);
39bec121
TW
4027 int value = cc3 ? cc3->value : operand->exp.X_add_number << 8;
4028
4029 if ((value & 0x0300) != value)
4030 {
4031 as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
4032 return 0;
4033 }
4034 insn->opcode[0].word |= value;
4035 return 1;
4036}
4037
4038static int
f1e7a2c9
NC
4039encode_arx (insn, operand)
4040 tic54x_insn *insn;
4041 struct opstruct *operand;
39bec121
TW
4042{
4043 int arf = strlen (operand->buf) >= 3 ? operand->buf[2] - '0' : -1;
f1e7a2c9 4044
39bec121
TW
4045 if (strncasecmp ("ar", operand->buf, 2) || arf < 0 || arf > 7)
4046 {
4047 as_bad (_("Invalid auxiliary register (use AR0-AR7)"));
4048 return 0;
4049 }
4050 insn->opcode[0].word |= arf;
4051 return 1;
4052}
4053
4054static int
f1e7a2c9
NC
4055encode_cc2 (insn, operand)
4056 tic54x_insn *insn;
4057 struct opstruct *operand;
39bec121 4058{
1aea3bb8 4059 symbol *cc2 = (symbol *) hash_find (cc2_hash, operand->buf);
f1e7a2c9 4060
39bec121
TW
4061 if (!cc2)
4062 {
4063 as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
4064 return 0;
4065 }
4066 insn->opcode[0].word |= cc2->value;
4067 return 1;
4068}
4069
4070static int
4071encode_operand (insn, type, operand)
1aea3bb8
NC
4072 tic54x_insn *insn;
4073 enum optype type;
4074 struct opstruct *operand;
39bec121 4075{
6e917903 4076 int ext = (insn->tm->flags & FL_EXT) != 0;
39bec121
TW
4077
4078 if (type == OP_MMR && operand->exp.X_op != O_constant)
4079 {
d0313fb7 4080 /* Disallow long-constant addressing for memory-mapped addressing. */
39bec121 4081 if (insn->is_lkaddr)
9a736b6b
NC
4082 {
4083 as_bad (_("lk addressing modes are invalid for memory-mapped "
4084 "register addressing"));
4085 return 0;
4086 }
39bec121 4087 type = OP_Smem;
d0313fb7 4088 /* Warn about *+ARx when used with MMR operands. */
39bec121 4089 if (strncasecmp (operand->buf, "*+ar", 4) == 0)
9a736b6b
NC
4090 {
4091 as_warn (_("Address mode *+ARx is not allowed in memory-mapped "
4092 "register addressing. Resulting behavior is "
4093 "undefined."));
4094 }
39bec121
TW
4095 }
4096
4097 switch (type)
4098 {
4099 case OP_None:
4100 return 1;
4101 case OP_dmad:
d0313fb7 4102 /* 16-bit immediate value. */
39bec121
TW
4103 return encode_dmad (insn, operand, 0);
4104 case OP_SRC:
3882b010 4105 if (TOUPPER (*operand->buf) == 'B')
9a736b6b
NC
4106 {
4107 insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 9);
4108 if (insn->using_default_dst)
4109 insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
4110 }
39bec121
TW
4111 return 1;
4112 case OP_RND:
5f5e16be 4113 /* Make sure this agrees with the OP_DST operand. */
3882b010 4114 if (!((TOUPPER (operand->buf[0]) == 'B') ^
9a736b6b
NC
4115 ((insn->opcode[0].word & (1 << 8)) != 0)))
4116 {
4117 as_bad (_("Destination accumulator for each part of this parallel "
4118 "instruction must be different"));
4119 return 0;
4120 }
39bec121
TW
4121 return 1;
4122 case OP_SRC1:
4123 case OP_DST:
3882b010 4124 if (TOUPPER (operand->buf[0]) == 'B')
9a736b6b 4125 insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
39bec121
TW
4126 return 1;
4127 case OP_Xmem:
4128 case OP_Ymem:
1aea3bb8 4129 {
9a736b6b
NC
4130 int mod = (operand->buf[4] == '\0' ? 0 : /* *arx */
4131 operand->buf[4] == '-' ? 1 : /* *arx- */
4132 operand->buf[5] == '\0' ? 2 : 3); /* *arx+, *arx+0% */
1aea3bb8
NC
4133 int arf = operand->buf[3] - '0' - 2;
4134 int code = (mod << 2) | arf;
4135 insn->opcode[0].word |= (code << (type == OP_Xmem ? 4 : 0));
4136 return 1;
4137 }
39bec121
TW
4138 case OP_Lmem:
4139 case OP_Smem:
4140 if (!is_indirect (operand))
9a736b6b
NC
4141 return encode_address (insn, operand);
4142 /* Fall through. */
39bec121
TW
4143 case OP_Sind:
4144 return encode_indirect (insn, operand);
4145 case OP_xpmad_ms7:
4146 return encode_dmad (insn, operand, 2);
4147 case OP_xpmad:
4148 return encode_dmad (insn, operand, 1);
4149 case OP_PA:
4150 case OP_pmad:
4151 return encode_dmad (insn, operand, 0);
4152 case OP_ARX:
4153 return encode_arx (insn, operand);
4154 case OP_MMRX:
4155 case OP_MMRY:
4156 case OP_MMR:
1aea3bb8
NC
4157 {
4158 int value = operand->exp.X_add_number;
4159
4160 if (type == OP_MMR)
4161 insn->opcode[0].word |= value;
4162 else
4163 {
4164 if (value < 16 || value > 24)
4165 {
4166 as_bad (_("Memory mapped register \"%s\" out of range"),
4167 operand->buf);
4168 return 0;
4169 }
4170 if (type == OP_MMRX)
4171 insn->opcode[0].word |= (value - 16) << 4;
4172 else
4173 insn->opcode[0].word |= (value - 16);
4174 }
4175 return 1;
39bec121 4176 }
39bec121
TW
4177 case OP_B:
4178 case OP_A:
4179 return 1;
4180 case OP_SHFT:
1aea3bb8 4181 return encode_integer (insn, operand, ext + insn->is_lkaddr,
9a736b6b 4182 0, 15, 0xF);
39bec121 4183 case OP_SHIFT:
1aea3bb8 4184 return encode_integer (insn, operand, ext + insn->is_lkaddr,
9a736b6b 4185 -16, 15, 0x1F);
39bec121
TW
4186 case OP_lk:
4187 return encode_integer (insn, operand, 1 + insn->is_lkaddr,
9a736b6b 4188 -32768, 32767, 0xFFFF);
39bec121
TW
4189 case OP_CC:
4190 return encode_condition (insn, operand);
4191 case OP_CC2:
4192 return encode_cc2 (insn, operand);
4193 case OP_CC3:
4194 return encode_cc3 (insn, operand);
4195 case OP_BITC:
4196 return encode_integer (insn, operand, 0, 0, 15, 0xF);
4197 case OP_k8:
4198 return encode_integer (insn, operand, 0, -128, 127, 0xFF);
4199 case OP_123:
1aea3bb8
NC
4200 {
4201 int value = operand->exp.X_add_number;
4202 int code;
4203 if (value < 1 || value > 3)
4204 {
4205 as_bad (_("Invalid operand (use 1, 2, or 3)"));
4206 return 0;
4207 }
4208 code = value == 1 ? 0 : value == 2 ? 0x2 : 0x1;
4209 insn->opcode[0].word |= (code << 8);
4210 return 1;
4211 }
39bec121
TW
4212 case OP_031:
4213 return encode_integer (insn, operand, 0, 0, 31, 0x1F);
4214 case OP_k8u:
4215 return encode_integer (insn, operand, 0, 0, 255, 0xFF);
4216 case OP_lku:
1aea3bb8 4217 return encode_integer (insn, operand, 1 + insn->is_lkaddr,
9a736b6b 4218 0, 65535, 0xFFFF);
39bec121 4219 case OP_SBIT:
1aea3bb8
NC
4220 {
4221 symbol *sbit = (symbol *) hash_find (sbit_hash, operand->buf);
4222 int value = is_absolute (operand) ?
4223 operand->exp.X_add_number : (sbit ? sbit->value : -1);
4224 int reg = 0;
4225
4226 if (insn->opcount == 1)
4227 {
4228 if (!sbit)
4229 {
4230 as_bad (_("A status register or status bit name is required"));
4231 return 0;
4232 }
4233 /* Guess the register based on the status bit; "ovb" is the last
4234 status bit defined for st0. */
4235 if (sbit > (symbol *) hash_find (sbit_hash, "ovb"))
4236 reg = 1;
4237 }
4238 if (value == -1)
4239 {
4240 as_bad (_("Unrecognized status bit \"%s\""), operand->buf);
4241 return 0;
4242 }
4243 insn->opcode[0].word |= value;
4244 insn->opcode[0].word |= (reg << 9);
4245 return 1;
4246 }
39bec121
TW
4247 case OP_N:
4248 if (strcasecmp (operand->buf, "st0") == 0
9a736b6b
NC
4249 || strcasecmp (operand->buf, "st1") == 0)
4250 {
4251 insn->opcode[0].word |=
4252 ((unsigned short) (operand->buf[2] - '0')) << 9;
4253 return 1;
4254 }
39bec121 4255 else if (operand->exp.X_op == O_constant
9a736b6b
NC
4256 && (operand->exp.X_add_number == 0
4257 || operand->exp.X_add_number == 1))
4258 {
4259 insn->opcode[0].word |=
4260 ((unsigned short) (operand->exp.X_add_number)) << 9;
4261 return 1;
4262 }
39bec121
TW
4263 as_bad (_("Invalid status register \"%s\""), operand->buf);
4264 return 0;
4265 case OP_k5:
4266 return encode_integer (insn, operand, 0, -16, 15, 0x1F);
4267 case OP_k3:
4268 return encode_integer (insn, operand, 0, 0, 7, 0x7);
4269 case OP_k9:
4270 return encode_integer (insn, operand, 0, 0, 0x1FF, 0x1FF);
4271 case OP_12:
1aea3bb8 4272 if (operand->exp.X_add_number != 1
9a736b6b
NC
4273 && operand->exp.X_add_number != 2)
4274 {
4275 as_bad (_("Operand \"%s\" out of range (use 1 or 2)"), operand->buf);
4276 return 0;
4277 }
39bec121
TW
4278 insn->opcode[0].word |= (operand->exp.X_add_number - 1) << 9;
4279 return 1;
4280 case OP_16:
4281 case OP_T:
4282 case OP_TS:
4283 case OP_ASM:
4284 case OP_TRN:
4285 case OP_DP:
4286 case OP_ARP:
d0313fb7 4287 /* No encoding necessary. */
39bec121
TW
4288 return 1;
4289 default:
4290 return 0;
4291 }
4292
4293 return 1;
4294}
4295
4296static void
f1e7a2c9
NC
4297emit_insn (insn)
4298 tic54x_insn *insn;
39bec121
TW
4299{
4300 int i;
6e917903
TW
4301 flagword oldflags = bfd_get_section_flags (stdoutput, now_seg);
4302 flagword flags = oldflags | SEC_CODE;
4303
4304 if (! bfd_set_section_flags (stdoutput, now_seg, flags))
4305 as_warn (_("error setting flags for \"%s\": %s"),
4306 bfd_section_name (stdoutput, now_seg),
4307 bfd_errmsg (bfd_get_error ()));
1aea3bb8
NC
4308
4309 for (i = 0; i < insn->words; i++)
39bec121 4310 {
1aea3bb8 4311 int size = (insn->opcode[i].unresolved
9a736b6b 4312 && insn->opcode[i].r_type == BFD_RELOC_TIC54X_23) ? 4 : 2;
39bec121
TW
4313 char *p = frag_more (size);
4314
4315 if (size == 2)
9a736b6b 4316 md_number_to_chars (p, (valueT) insn->opcode[i].word, 2);
39bec121 4317 else
9a736b6b 4318 md_number_to_chars (p, (valueT) insn->opcode[i].word << 16, 4);
1aea3bb8 4319
39bec121 4320 if (insn->opcode[i].unresolved)
9a736b6b
NC
4321 fix_new_exp (frag_now, p - frag_now->fr_literal,
4322 insn->opcode[i].r_nchars, &insn->opcode[i].addr_expr,
b34976b6 4323 FALSE, insn->opcode[i].r_type);
39bec121
TW
4324 }
4325}
4326
1aea3bb8 4327/* Convert the operand strings into appropriate opcode values
d0313fb7 4328 return the total number of words used by the instruction. */
9a736b6b 4329
39bec121 4330static int
f1e7a2c9
NC
4331build_insn (insn)
4332 tic54x_insn *insn;
39bec121
TW
4333{
4334 int i;
4335
d0313fb7 4336 /* Only non-parallel instructions support lk addressing. */
6e917903 4337 if (!(insn->tm->flags & FL_PAR))
39bec121 4338 {
1aea3bb8 4339 for (i = 0; i < insn->opcount; i++)
9a736b6b
NC
4340 {
4341 if ((OPTYPE (insn->operands[i].type) == OP_Smem
4342 || OPTYPE (insn->operands[i].type) == OP_Lmem
4343 || OPTYPE (insn->operands[i].type) == OP_Sind)
4344 && strchr (insn->operands[i].buf, '(')
4345 /* Don't mistake stack-relative addressing for lk addressing. */
4346 && strncasecmp (insn->operands[i].buf, "*sp (", 4) != 0)
4347 {
4348 insn->is_lkaddr = 1;
4349 insn->lkoperand = i;
4350 break;
4351 }
4352 }
39bec121 4353 }
6e917903 4354 insn->words = insn->tm->words + insn->is_lkaddr;
39bec121 4355
6e917903
TW
4356 insn->opcode[0].word = insn->tm->opcode;
4357 if (insn->tm->flags & FL_EXT)
1aea3bb8 4358 insn->opcode[1 + insn->is_lkaddr].word = insn->tm->opcode2;
39bec121 4359
9a736b6b 4360 for (i = 0; i < insn->opcount; i++)
39bec121
TW
4361 {
4362 enum optype type = insn->operands[i].type;
f1e7a2c9 4363
39bec121 4364 if (!encode_operand (insn, type, &insn->operands[i]))
9a736b6b 4365 return 0;
39bec121 4366 }
6e917903 4367 if (insn->tm->flags & FL_PAR)
9a736b6b
NC
4368 for (i = 0; i < insn->paropcount; i++)
4369 {
4370 enum optype partype = insn->paroperands[i].type;
f1e7a2c9 4371
9a736b6b
NC
4372 if (!encode_operand (insn, partype, &insn->paroperands[i]))
4373 return 0;
4374 }
39bec121
TW
4375
4376 emit_insn (insn);
4377
4378 return insn->words;
4379}
4380
4381static int
f1e7a2c9
NC
4382optimize_insn (insn)
4383 tic54x_insn *insn;
39bec121 4384{
1aea3bb8 4385 /* Optimize some instructions, helping out the brain-dead programmer. */
39bec121
TW
4386#define is_zero(op) ((op).exp.X_op == O_constant && (op).exp.X_add_number == 0)
4387 if (strcasecmp (insn->tm->name, "add") == 0)
4388 {
9a736b6b
NC
4389 if (insn->opcount > 1
4390 && is_accumulator (&insn->operands[insn->opcount - 2])
4391 && is_accumulator (&insn->operands[insn->opcount - 1])
4392 && strcasecmp (insn->operands[insn->opcount - 2].buf,
4393 insn->operands[insn->opcount - 1].buf) == 0)
4394 {
4395 --insn->opcount;
4396 insn->using_default_dst = 1;
4397 return 1;
4398 }
1aea3bb8 4399
d0313fb7 4400 /* Try to collapse if Xmem and shift count is zero. */
9a736b6b
NC
4401 if ((OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
4402 && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT
4403 && is_zero (insn->operands[1]))
4404 /* Or if Smem, shift is zero or absent, and SRC == DST. */
4405 || (OPTYPE (insn->tm->operand_types[0]) == OP_Smem
4406 && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
4407 && is_type (&insn->operands[1], OP_SHIFT)
4408 && is_zero (insn->operands[1]) && insn->opcount == 3))
4409 {
4410 insn->operands[1] = insn->operands[2];
4411 insn->opcount = 2;
4412 return 1;
4413 }
39bec121
TW
4414 }
4415 else if (strcasecmp (insn->tm->name, "ld") == 0)
4416 {
4417 if (insn->opcount == 3 && insn->operands[0].type != OP_SRC)
9a736b6b
NC
4418 {
4419 if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
4420 || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
4421 && is_zero (insn->operands[1])
4422 && (OPTYPE (insn->tm->operand_types[0]) != OP_lk
4423 || (insn->operands[0].exp.X_op == O_constant
4424 && insn->operands[0].exp.X_add_number <= 255
4425 && insn->operands[0].exp.X_add_number >= 0)))
4426 {
4427 insn->operands[1] = insn->operands[2];
4428 insn->opcount = 2;
4429 return 1;
4430 }
4431 }
4432 }
4433 else if (strcasecmp (insn->tm->name, "sth") == 0
4434 || strcasecmp (insn->tm->name, "stl") == 0)
4435 {
4436 if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
4437 || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
4438 && is_zero (insn->operands[1]))
4439 {
4440 insn->operands[1] = insn->operands[2];
4441 insn->opcount = 2;
4442 return 1;
4443 }
39bec121
TW
4444 }
4445 else if (strcasecmp (insn->tm->name, "sub") == 0)
4446 {
9a736b6b
NC
4447 if (insn->opcount > 1
4448 && is_accumulator (&insn->operands[insn->opcount - 2])
4449 && is_accumulator (&insn->operands[insn->opcount - 1])
4450 && strcasecmp (insn->operands[insn->opcount - 2].buf,
4451 insn->operands[insn->opcount - 1].buf) == 0)
4452 {
4453 --insn->opcount;
4454 insn->using_default_dst = 1;
4455 return 1;
4456 }
4457
f1e7a2c9 4458 if ( ((OPTYPE (insn->tm->operand_types[0]) == OP_Smem
9a736b6b
NC
4459 && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT)
4460 || (OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
f1e7a2c9 4461 && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT))
9a736b6b
NC
4462 && is_zero (insn->operands[1])
4463 && insn->opcount == 3)
4464 {
4465 insn->operands[1] = insn->operands[2];
4466 insn->opcount = 2;
4467 return 1;
4468 }
39bec121
TW
4469 }
4470 return 0;
4471}
4472
d0313fb7 4473/* Find a matching template if possible, and get the operand strings. */
9a736b6b 4474
39bec121 4475static int
f1e7a2c9
NC
4476tic54x_parse_insn (insn, line)
4477 tic54x_insn *insn;
4478 char *line;
39bec121 4479{
1aea3bb8 4480 insn->tm = (template *) hash_find (op_hash, insn->mnemonic);
39bec121
TW
4481 if (!insn->tm)
4482 {
4483 as_bad (_("Unrecognized instruction \"%s\""), insn->mnemonic);
4484 return 0;
4485 }
4486
4487 insn->opcount = get_operands (insn->operands, line);
4488 if (insn->opcount < 0)
1aea3bb8 4489 return 0;
39bec121 4490
d0313fb7 4491 /* Check each variation of operands for this mnemonic. */
39bec121
TW
4492 while (insn->tm->name && strcasecmp (insn->tm->name, insn->mnemonic) == 0)
4493 {
9a736b6b
NC
4494 if (insn->opcount >= insn->tm->minops
4495 && insn->opcount <= insn->tm->maxops
4496 && operands_match (insn, &insn->operands[0], insn->opcount,
4497 insn->tm->operand_types,
4498 insn->tm->minops, insn->tm->maxops))
4499 {
4500 /* SUCCESS! now try some optimizations. */
4501 if (optimize_insn (insn))
4502 {
4503 insn->tm = (template *) hash_find (op_hash,
1aea3bb8 4504 insn->mnemonic);
9a736b6b
NC
4505 continue;
4506 }
39bec121 4507
9a736b6b
NC
4508 return 1;
4509 }
39bec121
TW
4510 ++(insn->tm);
4511 }
1aea3bb8
NC
4512 as_bad (_("Unrecognized operand list '%s' for instruction '%s'"),
4513 line, insn->mnemonic);
39bec121
TW
4514 return 0;
4515}
4516
d0313fb7
NC
4517/* We set this in start_line_hook, 'cause if we do a line replacement, we
4518 won't be able to see the next line. */
39bec121 4519static int parallel_on_next_line_hint = 0;
9a736b6b 4520
39bec121 4521/* See if this is part of a parallel instruction
d0313fb7 4522 Look for a subsequent line starting with "||". */
9a736b6b 4523
39bec121 4524static int
f1e7a2c9
NC
4525next_line_shows_parallel (next_line)
4526 char *next_line;
39bec121 4527{
9a736b6b 4528 /* Look for the second half. */
3882b010 4529 while (ISSPACE (*next_line))
39bec121
TW
4530 ++next_line;
4531
9a736b6b
NC
4532 return (next_line[0] == PARALLEL_SEPARATOR
4533 && next_line[1] == PARALLEL_SEPARATOR);
39bec121
TW
4534}
4535
4536static int
f1e7a2c9
NC
4537tic54x_parse_parallel_insn_firstline (insn, line)
4538 tic54x_insn *insn;
4539 char *line;
39bec121 4540{
6e917903
TW
4541 insn->tm = (template *) hash_find (parop_hash, insn->mnemonic);
4542 if (!insn->tm)
39bec121 4543 {
1aea3bb8 4544 as_bad (_("Unrecognized parallel instruction \"%s\""),
9a736b6b 4545 insn->mnemonic);
39bec121
TW
4546 return 0;
4547 }
4548
6e917903
TW
4549 while (insn->tm->name && strcasecmp (insn->tm->name,
4550 insn->mnemonic) == 0)
39bec121
TW
4551 {
4552 insn->opcount = get_operands (insn->operands, line);
4553 if (insn->opcount < 0)
9a736b6b
NC
4554 return 0;
4555 if (insn->opcount == 2
4556 && operands_match (insn, &insn->operands[0], insn->opcount,
6e917903 4557 insn->tm->operand_types, 2, 2))
9a736b6b
NC
4558 {
4559 return 1;
4560 }
6e917903 4561 ++(insn->tm);
39bec121 4562 }
d0313fb7 4563 /* Didn't find a matching parallel; try for a normal insn. */
39bec121
TW
4564 return 0;
4565}
4566
d0313fb7 4567/* Parse the second line of a two-line parallel instruction. */
9a736b6b 4568
39bec121 4569static int
f1e7a2c9
NC
4570tic54x_parse_parallel_insn_lastline (insn, line)
4571 tic54x_insn *insn;
4572 char *line;
39bec121
TW
4573{
4574 int valid_mnemonic = 0;
1aea3bb8 4575
39bec121 4576 insn->paropcount = get_operands (insn->paroperands, line);
6e917903 4577 while (insn->tm->name && strcasecmp (insn->tm->name,
9a736b6b 4578 insn->mnemonic) == 0)
39bec121 4579 {
6e917903 4580 if (strcasecmp (insn->tm->parname, insn->parmnemonic) == 0)
9a736b6b
NC
4581 {
4582 valid_mnemonic = 1;
f1e7a2c9 4583
6e917903
TW
4584 if (insn->paropcount >= insn->tm->minops
4585 && insn->paropcount <= insn->tm->maxops
9a736b6b
NC
4586 && operands_match (insn, insn->paroperands,
4587 insn->paropcount,
6e917903
TW
4588 insn->tm->paroperand_types,
4589 insn->tm->minops, insn->tm->maxops))
f1e7a2c9 4590 return 1;
9a736b6b 4591 }
6e917903 4592 ++(insn->tm);
39bec121
TW
4593 }
4594 if (valid_mnemonic)
4595 as_bad (_("Invalid operand (s) for parallel instruction \"%s\""),
9a736b6b 4596 insn->parmnemonic);
39bec121
TW
4597 else
4598 as_bad (_("Unrecognized parallel instruction combination \"%s || %s\""),
9a736b6b 4599 insn->mnemonic, insn->parmnemonic);
39bec121
TW
4600
4601 return 0;
4602}
4603
d0313fb7 4604/* If quotes found, return copy of line up to closing quote;
9a736b6b
NC
4605 otherwise up until terminator.
4606 If it's a string, pass as-is; otherwise attempt substitution symbol
d0313fb7 4607 replacement on the value. */
9a736b6b 4608
39bec121 4609static char *
f1e7a2c9
NC
4610subsym_get_arg (line, terminators, str, nosub)
4611 char *line;
4612 char *terminators;
4613 char **str;
4614 int nosub;
39bec121
TW
4615{
4616 char *ptr = line;
4617 char *endp;
4618 int is_string = *line == '"';
3882b010 4619 int is_char = ISDIGIT (*line);
39bec121
TW
4620
4621 if (is_char)
4622 {
3882b010 4623 while (ISDIGIT (*ptr))
9a736b6b 4624 ++ptr;
39bec121
TW
4625 endp = ptr;
4626 *str = xmalloc (ptr - line + 1);
4627 strncpy (*str, line, ptr - line);
4628 (*str)[ptr - line] = 0;
4629 }
4630 else if (is_string)
4631 {
4632 char *savedp = input_line_pointer;
4633 int len;
f1e7a2c9 4634
39bec121
TW
4635 input_line_pointer = ptr;
4636 *str = demand_copy_C_string (&len);
4637 endp = input_line_pointer;
4638 input_line_pointer = savedp;
4639
d0313fb7 4640 /* Do forced substitutions if requested. */
39bec121 4641 if (!nosub && **str == ':')
9a736b6b 4642 *str = subsym_substitute (*str, 1);
39bec121
TW
4643 }
4644 else
4645 {
4646 char *term = terminators;
4647 char *value = NULL;
4648
4649 while (*ptr && *ptr != *term)
9a736b6b
NC
4650 {
4651 if (!*term)
4652 {
4653 term = terminators;
4654 ++ptr;
4655 }
4656 else
4657 ++term;
4658 }
39bec121
TW
4659 endp = ptr;
4660 *str = xmalloc (ptr - line + 1);
4661 strncpy (*str, line, ptr - line);
4662 (*str)[ptr - line] = 0;
d0313fb7 4663 /* Do simple substitution, if available. */
39bec121 4664 if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
1aea3bb8 4665 *str = value;
39bec121
TW
4666 }
4667
4668 return endp;
4669}
4670
d0313fb7 4671/* Replace the given substitution string.
39bec121
TW
4672 We start at the innermost macro level, so that existing locals remain local
4673 Note: we're treating macro args identically to .var's; I don't know if
d0313fb7 4674 that's compatible w/TI's assembler. */
9a736b6b 4675
39bec121 4676static void
d0313fb7
NC
4677subsym_create_or_replace (name, value)
4678 char *name;
4679 char *value;
39bec121
TW
4680{
4681 int i;
4682
1aea3bb8 4683 for (i = macro_level; i > 0; i--)
39bec121
TW
4684 {
4685 if (hash_find (subsym_hash[i], name))
9a736b6b
NC
4686 {
4687 hash_replace (subsym_hash[i], name, value);
4688 return;
4689 }
39bec121
TW
4690 }
4691 if (hash_find (subsym_hash[0], name))
4692 hash_replace (subsym_hash[0], name, value);
4693 else
4694 hash_insert (subsym_hash[0], name, value);
4695}
4696
9a736b6b 4697/* Look up the substitution string replacement for the given symbol.
33b7f697 4698 Start with the innermost macro substitution table given and work
9a736b6b
NC
4699 outwards. */
4700
39bec121 4701static char *
d0313fb7
NC
4702subsym_lookup (name, nest_level)
4703 char *name;
4704 int nest_level;
39bec121
TW
4705{
4706 char *value = hash_find (subsym_hash[nest_level], name);
4707
4708 if (value || nest_level == 0)
4709 return value;
4710
1aea3bb8 4711 return subsym_lookup (name, nest_level - 1);
39bec121
TW
4712}
4713
d0313fb7 4714/* Do substitution-symbol replacement on the given line (recursively).
1aea3bb8 4715 return the argument if no substitution was done
39bec121
TW
4716
4717 Also look for built-in functions ($func (arg)) and local labels.
4718
d0313fb7 4719 If FORCED is set, look for forced substitutions of the form ':SYMBOL:'. */
9a736b6b 4720
39bec121 4721static char *
f1e7a2c9
NC
4722subsym_substitute (line, forced)
4723 char * line;
4724 int forced;
39bec121 4725{
d0313fb7
NC
4726 /* For each apparent symbol, see if it's a substitution symbol, and if so,
4727 replace it in the input. */
9a736b6b
NC
4728 char *replacement; /* current replacement for LINE. */
4729 char *head; /* Start of line. */
4730 char *ptr; /* Current examination point. */
4731 int changed = 0; /* Did we make a substitution? */
4732 int eval_line = 0; /* Is this line a .eval/.asg statement? */
4733 int eval_symbol = 0; /* Are we in the middle of the symbol for
4734 .eval/.asg? */
39bec121
TW
4735 char *eval_end = NULL;
4736 int recurse = 1;
4737 int line_conditional = 0;
4738 char *tmp;
4739
d0313fb7 4740 /* Work with a copy of the input line. */
39bec121
TW
4741 replacement = xmalloc (strlen (line) + 1);
4742 strcpy (replacement, line);
4743
4744 ptr = head = replacement;
4745
d0313fb7 4746 /* Flag lines where we might need to replace a single '=' with two;
39bec121 4747 GAS uses single '=' to assign macro args values, and possibly other
d0313fb7 4748 places, so limit what we replace. */
1aea3bb8
NC
4749 if (strstr (line, ".if")
4750 || strstr (line, ".elseif")
39bec121 4751 || strstr (line, ".break"))
f1e7a2c9 4752 line_conditional = 1;
39bec121 4753
d0313fb7
NC
4754 /* Watch out for .eval, so that we avoid doing substitution on the
4755 symbol being assigned a value. */
39bec121 4756 if (strstr (line, ".eval") || strstr (line, ".asg"))
1aea3bb8 4757 eval_line = 1;
39bec121 4758
9a736b6b
NC
4759 /* If it's a macro definition, don't do substitution on the argument
4760 names. */
39bec121
TW
4761 if (strstr (line, ".macro"))
4762 return line;
4763
1aea3bb8 4764 while (!is_end_of_line[(int) *ptr])
39bec121
TW
4765 {
4766 int current_char = *ptr;
4767
d0313fb7 4768 /* Need to update this since LINE may have been modified. */
39bec121 4769 if (eval_line)
1aea3bb8 4770 eval_end = strrchr (ptr, ',');
39bec121 4771
d0313fb7 4772 /* Replace triple double quotes with bounding quote/escapes. */
39bec121 4773 if (current_char == '"' && ptr[1] == '"' && ptr[2] == '"')
9a736b6b
NC
4774 {
4775 ptr[1] = '\\';
4776 tmp = strstr (ptr + 2, "\"\"\"");
4777 if (tmp)
4778 tmp[0] = '\\';
4779 changed = 1;
4780 }
39bec121 4781
d0313fb7 4782 /* Replace a single '=' with a '==';
9a736b6b 4783 for compatibility with older code only. */
1aea3bb8 4784 if (line_conditional && current_char == '=')
9a736b6b
NC
4785 {
4786 if (ptr[1] == '=')
4787 {
4788 ptr += 2;
4789 continue;
4790 }
4791 *ptr++ = '\0';
4792 tmp = xmalloc (strlen (head) + 2 + strlen (ptr) + 1);
4793 sprintf (tmp, "%s==%s", head, ptr);
4794 /* Continue examining after the '=='. */
4795 ptr = tmp + strlen (head) + 2;
4796 free (replacement);
4797 head = replacement = tmp;
4798 changed = 1;
4799 }
39bec121 4800
d0313fb7 4801 /* Flag when we've reached the symbol part of .eval/.asg. */
39bec121 4802 if (eval_line && ptr >= eval_end)
9a736b6b 4803 eval_symbol = 1;
39bec121 4804
d0313fb7 4805 /* For each apparent symbol, see if it's a substitution symbol, and if
9a736b6b 4806 so, replace it in the input. */
39bec121 4807 if ((forced && current_char == ':')
9a736b6b
NC
4808 || (!forced && is_name_beginner (current_char)))
4809 {
4810 char *name; /* Symbol to be replaced. */
4811 char *savedp = input_line_pointer;
4812 int c;
4813 char *value = NULL;
4814 char *tail; /* Rest of line after symbol. */
4815
4816 /* Skip the colon. */
4817 if (forced)
4818 ++ptr;
4819
4820 name = input_line_pointer = ptr;
4821 c = get_symbol_end ();
4822 /* '?' is not normally part of a symbol, but it IS part of a local
4823 label. */
4824 if (c == '?')
4825 {
4826 *input_line_pointer++ = c;
4827 c = *input_line_pointer;
4828 *input_line_pointer = '\0';
4829 }
4830 /* Avoid infinite recursion; if a symbol shows up a second time for
4831 substitution, leave it as is. */
4832 if (hash_find (subsym_recurse_hash, name) == NULL)
4833 value = subsym_lookup (name, macro_level);
4834 else
4835 as_warn (_("%s symbol recursion stopped at "
4836 "second appearance of '%s'"),
4837 forced ? "Forced substitution" : "Substitution", name);
4838 ptr = tail = input_line_pointer;
4839 input_line_pointer = savedp;
4840
4841 /* Check for local labels; replace them with the appropriate
4842 substitution. */
3882b010 4843 if ((*name == '$' && ISDIGIT (name[1]) && name[2] == '\0')
9a736b6b
NC
4844 || name[strlen (name) - 1] == '?')
4845 {
4846 /* Use an existing identifier for that label if, available, or
4847 create a new, unique identifier. */
4848 value = hash_find (local_label_hash[macro_level], name);
4849 if (value == NULL)
4850 {
4851 char digit[11];
4852 char *namecopy = strcpy (xmalloc (strlen (name) + 1), name);
f1e7a2c9 4853
9a736b6b
NC
4854 value = strcpy (xmalloc (strlen (name) + sizeof (digit) + 1),
4855 name);
4856 if (*value != '$')
4857 value[strlen (value) - 1] = '\0';
4858 sprintf (digit, ".%d", local_label_id++);
4859 strcat (value, digit);
4860 hash_insert (local_label_hash[macro_level], namecopy, value);
4861 }
4862 /* Indicate where to continue looking for substitutions. */
4863 ptr = tail;
4864 }
4865 /* Check for built-in subsym and math functions. */
4866 else if (value != NULL && *name == '$')
4867 {
4868 subsym_proc_entry *entry = (subsym_proc_entry *) value;
4869 math_proc_entry *math_entry = hash_find (math_hash, name);
4870 char *arg1, *arg2 = NULL;
4871
4872 *ptr = c;
4873 if (entry == NULL)
4874 {
4875 as_bad (_("Unrecognized substitution symbol function"));
4876 break;
4877 }
4878 else if (*ptr != '(')
4879 {
4880 as_bad (_("Missing '(' after substitution symbol function"));
4881 break;
4882 }
4883 ++ptr;
4884 if (math_entry != NULL)
4885 {
4886 float arg1, arg2 = 0;
4887 volatile float fresult;
4888
4889 arg1 = (float) strtod (ptr, &ptr);
4890 if (math_entry->nargs == 2)
4891 {
4892 if (*ptr++ != ',')
4893 {
4894 as_bad (_("Expecting second argument"));
4895 break;
4896 }
4897 arg2 = (float) strtod (ptr, &ptr);
4898 }
4899 fresult = (*math_entry->proc) (arg1, arg2);
4900 value = xmalloc (128);
4901 if (math_entry->int_return)
4902 sprintf (value, "%d", (int) fresult);
4903 else
4904 sprintf (value, "%f", fresult);
4905 if (*ptr++ != ')')
4906 {
4907 as_bad (_("Extra junk in function call, expecting ')'"));
4908 break;
4909 }
4910 /* Don't bother recursing; the replacement isn't a
4911 symbol. */
4912 recurse = 0;
4913 }
4914 else
4915 {
4916 int val;
4917 int arg_type[2] = { *ptr == '"' , 0 };
4918 int ismember = !strcmp (entry->name, "$ismember");
f1e7a2c9 4919
9a736b6b
NC
4920 /* Parse one or two args, which must be a substitution
4921 symbol, string or a character-string constant. */
4922 /* For all functions, a string or substitution symbol may be
4923 used, with the following exceptions:
4924 firstch/lastch: 2nd arg must be character constant
4925 ismember: both args must be substitution symbols. */
4926 ptr = subsym_get_arg (ptr, ",)", &arg1, ismember);
4927 if (!arg1)
4928 break;
4929 if (entry->nargs == 2)
4930 {
4931 if (*ptr++ != ',')
4932 {
4933 as_bad (_("Function expects two arguments"));
4934 break;
4935 }
4936 /* Character constants are converted to numerics
4937 by the preprocessor. */
3882b010 4938 arg_type[1] = (ISDIGIT (*ptr)) ? 2 : (*ptr == '"');
9a736b6b
NC
4939 ptr = subsym_get_arg (ptr, ")", &arg2, ismember);
4940 }
4941 /* Args checking. */
4942 if ((!strcmp (entry->name, "$firstch")
4943 || !strcmp (entry->name, "$lastch"))
4944 && arg_type[1] != 2)
4945 {
4946 as_bad (_("Expecting character constant argument"));
4947 break;
4948 }
4949 if (ismember
4950 && (arg_type[0] != 0 || arg_type[1] != 0))
4951 {
4952 as_bad (_("Both arguments must be substitution symbols"));
4953 break;
4954 }
4955 if (*ptr++ != ')')
4956 {
4957 as_bad (_("Extra junk in function call, expecting ')'"));
4958 break;
4959 }
4960 val = (*entry->proc) (arg1, arg2);
4961 value = xmalloc (64);
4962 sprintf (value, "%d", val);
4963 }
4964 /* Fix things up to replace the entire expression, not just the
4965 function name. */
4966 tail = ptr;
4967 c = *tail;
4968 }
4969
4970 if (value != NULL && !eval_symbol)
4971 {
4972 /* Replace the symbol with its string replacement and
4973 continue. Recursively replace VALUE until either no
4974 substitutions are performed, or a substitution that has been
4975 previously made is encountered again.
4976
4977 put the symbol into the recursion hash table so we only
4978 try to replace a symbol once. */
4979 if (recurse)
4980 {
4981 hash_insert (subsym_recurse_hash, name, name);
4982 value = subsym_substitute (value, macro_level > 0);
4983 hash_delete (subsym_recurse_hash, name);
4984 }
4985
4986 /* Temporarily zero-terminate where the symbol started. */
4987 *name = 0;
4988 if (forced)
4989 {
4990 if (c == '(')
4991 {
4992 /* Subscripted substitution symbol -- use just the
4993 indicated portion of the string; the description
33b7f697 4994 kinda indicates that forced substitution is not
9a736b6b
NC
4995 supposed to be recursive, but I'm not sure. */
4996 unsigned beg, len = 1; /* default to a single char */
4997 char *newval = strcpy (xmalloc (strlen (value) + 1),
4998 value);
4999
5000 savedp = input_line_pointer;
5001 input_line_pointer = tail + 1;
5002 beg = get_absolute_expression ();
5003 if (beg < 1)
5004 {
5005 as_bad (_("Invalid subscript (use 1 to %d)"),
5006 strlen (value));
5007 break;
5008 }
5009 if (*input_line_pointer == ',')
5010 {
5011 ++input_line_pointer;
5012 len = get_absolute_expression ();
5013 if (beg + len > strlen (value))
5014 {
5015 as_bad (_("Invalid length (use 0 to %d"),
1aea3bb8 5016 strlen (value) - beg);
9a736b6b
NC
5017 break;
5018 }
5019 }
5020 newval += beg - 1;
5021 newval[len] = 0;
5022 tail = input_line_pointer;
5023 if (*tail++ != ')')
5024 {
5025 as_bad (_("Missing ')' in subscripted substitution "
5026 "symbol expression"));
5027 break;
5028 }
5029 c = *tail;
5030 input_line_pointer = savedp;
5031
5032 value = newval;
5033 }
5034 name[-1] = 0;
5035 }
5036 tmp = xmalloc (strlen (head) + strlen (value) +
5037 strlen (tail + 1) + 2);
5038 strcpy (tmp, head);
5039 strcat (tmp, value);
5040 /* Make sure forced substitutions are properly terminated. */
5041 if (forced)
5042 {
5043 if (c != ':')
5044 {
5045 as_bad (_("Missing forced substitution terminator ':'"));
5046 break;
5047 }
5048 ++tail;
9a736b6b
NC
5049 }
5050 else
5051 /* Restore the character after the symbol end. */
5052 *tail = c;
5053 strcat (tmp, tail);
5054 /* Continue examining after the replacement value. */
5055 ptr = tmp + strlen (head) + strlen (value);
5056 free (replacement);
5057 head = replacement = tmp;
5058 changed = 1;
5059 }
5060 else
5061 *ptr = c;
5062 }
39bec121 5063 else
9a736b6b
NC
5064 {
5065 ++ptr;
5066 }
39bec121
TW
5067 }
5068
5069 if (changed)
5070 return replacement;
5071 else
5072 return line;
5073}
5074
1aea3bb8 5075/* We use this to handle substitution symbols
39bec121
TW
5076 hijack input_line_pointer, replacing it with our substituted string.
5077
5078 .sslist should enable listing the line after replacements are made...
5079
d0313fb7 5080 returns the new buffer limit. */
9a736b6b 5081
39bec121
TW
5082void
5083tic54x_start_line_hook ()
5084{
5085 char *line, *endp;
5086 char *replacement = NULL;
5087
d0313fb7 5088 /* Work with a copy of the input line, including EOL char. */
39bec121 5089 endp = input_line_pointer;
1aea3bb8 5090 while (!is_end_of_line[(int) *endp++])
39bec121
TW
5091 ;
5092 line = xmalloc (endp - input_line_pointer + 1);
5093 strncpy (line, input_line_pointer, endp - input_line_pointer + 1);
5094 line[endp - input_line_pointer] = 0;
5095
d0313fb7 5096 /* Scan ahead for parallel insns. */
39bec121
TW
5097 parallel_on_next_line_hint = next_line_shows_parallel (endp + 1);
5098
d0313fb7 5099 /* If within a macro, first process forced replacements. */
39bec121
TW
5100 if (macro_level > 0)
5101 replacement = subsym_substitute (line, 1);
5102 else
5103 replacement = line;
5104 replacement = subsym_substitute (replacement, 0);
5105
5106 if (replacement != line)
5107 {
5108 char *tmp = replacement;
9a736b6b 5109 char *comment = strchr (replacement, ';');
1aea3bb8 5110 char endc = replacement[strlen (replacement) - 1];
39bec121 5111
d0313fb7 5112 /* Clean up the replacement; we'd prefer to have this done by the
9a736b6b
NC
5113 standard preprocessing equipment (maybe do_scrub_chars?)
5114 but for now, do a quick-and-dirty. */
39bec121 5115 if (comment != NULL)
9a736b6b
NC
5116 {
5117 comment[0] = endc;
5118 comment[1] = 0;
5119 --comment;
5120 }
1aea3bb8 5121 else
9a736b6b 5122 comment = replacement + strlen (replacement) - 1;
39bec121 5123
d0313fb7 5124 /* Trim trailing whitespace. */
3882b010 5125 while (ISSPACE (*comment))
9a736b6b
NC
5126 {
5127 comment[0] = endc;
5128 comment[1] = 0;
5129 --comment;
5130 }
39bec121 5131
d0313fb7 5132 /* Compact leading whitespace. */
3882b010 5133 while (ISSPACE (tmp[0]) && ISSPACE (tmp[1]))
9a736b6b 5134 ++tmp;
39bec121
TW
5135
5136 input_line_pointer = endp;
5137 input_scrub_insert_line (tmp);
5138 free (replacement);
5139 free (line);
d0313fb7 5140 /* Keep track of whether we've done a substitution. */
39bec121
TW
5141 substitution_line = 1;
5142 }
5143 else
5144 {
d0313fb7 5145 /* No change. */
39bec121
TW
5146 free (line);
5147 substitution_line = 0;
5148 }
5149}
5150
5151/* This is the guts of the machine-dependent assembler. STR points to a
5152 machine dependent instruction. This function is supposed to emit
d0313fb7 5153 the frags/bytes it assembles to. */
39bec121
TW
5154void
5155md_assemble (line)
1aea3bb8 5156 char *line;
39bec121
TW
5157{
5158 static int repeat_slot = 0;
9a736b6b 5159 static int delay_slots = 0; /* How many delay slots left to fill? */
39bec121
TW
5160 static int is_parallel = 0;
5161 static tic54x_insn insn;
5162 char *lptr;
5163 char *savedp = input_line_pointer;
5164 int c;
5165
5166 input_line_pointer = line;
5167 c = get_symbol_end ();
5168
5169 if (cpu == VNONE)
5170 cpu = V542;
5171 if (address_mode_needs_set)
5172 {
5173 set_address_mode (amode);
5174 address_mode_needs_set = 0;
5175 }
5176 if (cpu_needs_set)
5177 {
5178 set_cpu (cpu);
5179 cpu_needs_set = 0;
5180 }
5181 assembly_begun = 1;
5182
5183 if (is_parallel)
5184 {
5185 is_parallel = 0;
5186
5187 strcpy (insn.parmnemonic, line);
5188 lptr = input_line_pointer;
5189 *lptr = c;
5190 input_line_pointer = savedp;
5191
5192 if (tic54x_parse_parallel_insn_lastline (&insn, lptr))
9a736b6b
NC
5193 {
5194 int words = build_insn (&insn);
5195
5196 if (delay_slots != 0)
5197 {
5198 if (words > delay_slots)
5199 {
5200 as_bad (_("Instruction does not fit in available delay "
5201 "slots (%d-word insn, %d slots left)"),
1aea3bb8 5202 words, delay_slots);
9a736b6b
NC
5203 delay_slots = 0;
5204 return;
5205 }
5206 delay_slots -= words;
5207 }
5208 }
39bec121
TW
5209 return;
5210 }
5211
5212 memset (&insn, 0, sizeof (insn));
5213 strcpy (insn.mnemonic, line);
5214 lptr = input_line_pointer;
5215 *lptr = c;
5216 input_line_pointer = savedp;
1aea3bb8 5217
39bec121
TW
5218 /* See if this line is part of a parallel instruction; if so, either this
5219 line or the next line will have the "||" specifier preceding the
d0313fb7 5220 mnemonic, and we look for it in the parallel insn hash table. */
39bec121
TW
5221 if (strstr (line, "||") != NULL || parallel_on_next_line_hint)
5222 {
5223 char *tmp = strstr (line, "||");
5224 if (tmp != NULL)
9a736b6b 5225 *tmp = '\0';
39bec121
TW
5226
5227 if (tic54x_parse_parallel_insn_firstline (&insn, lptr))
9a736b6b
NC
5228 {
5229 is_parallel = 1;
5230 /* If the parallel part is on the same line, process it now,
5231 otherwise let the assembler pick up the next line for us. */
5232 if (tmp != NULL)
5233 {
3882b010 5234 while (ISSPACE (tmp[2]))
9a736b6b
NC
5235 ++tmp;
5236 md_assemble (tmp + 2);
5237 }
5238 }
39bec121 5239 else
9a736b6b
NC
5240 {
5241 as_bad (_("Unrecognized parallel instruction '%s'"), line);
5242 }
39bec121
TW
5243 return;
5244 }
5245
5246 if (tic54x_parse_insn (&insn, lptr))
5247 {
5248 int words;
5249
1aea3bb8 5250 if ((insn.tm->flags & FL_LP)
9a736b6b
NC
5251 && cpu != V545LP && cpu != V546LP)
5252 {
5253 as_bad (_("Instruction '%s' requires an LP cpu version"),
5254 insn.tm->name);
5255 return;
5256 }
1aea3bb8 5257 if ((insn.tm->flags & FL_FAR)
9a736b6b
NC
5258 && amode != far_mode)
5259 {
5260 as_bad (_("Instruction '%s' requires far mode addressing"),
5261 insn.tm->name);
5262 return;
5263 }
39bec121
TW
5264
5265 words = build_insn (&insn);
5266
d0313fb7 5267 /* Is this instruction in a delay slot? */
39bec121 5268 if (delay_slots)
9a736b6b
NC
5269 {
5270 if (words > delay_slots)
5271 {
5272 as_warn (_("Instruction does not fit in available delay "
5273 "slots (%d-word insn, %d slots left). "
5274 "Resulting behavior is undefined."),
5275 words, delay_slots);
5276 delay_slots = 0;
5277 return;
5278 }
5279 /* Branches in delay slots are not allowed. */
5280 if (insn.tm->flags & FL_BMASK)
5281 {
5282 as_warn (_("Instructions which cause PC discontinuity are not "
5283 "allowed in a delay slot. "
5284 "Resulting behavior is undefined."));
5285 }
5286 delay_slots -= words;
5287 }
5288
5289 /* Is this instruction the target of a repeat? */
39bec121 5290 if (repeat_slot)
9a736b6b
NC
5291 {
5292 if (insn.tm->flags & FL_NR)
5293 as_warn (_("'%s' is not repeatable. "
5294 "Resulting behavior is undefined."),
5295 insn.tm->name);
5296 else if (insn.is_lkaddr)
5297 as_warn (_("Instructions using long offset modifiers or absolute "
5298 "addresses are not repeatable. "
5299 "Resulting behavior is undefined."));
5300 repeat_slot = 0;
5301 }
1aea3bb8 5302
d0313fb7 5303 /* Make sure we check the target of a repeat instruction. */
39bec121 5304 if (insn.tm->flags & B_REPEAT)
9a736b6b
NC
5305 {
5306 repeat_slot = 1;
5307 /* FIXME -- warn if repeat_slot == 1 at EOF. */
5308 }
d0313fb7 5309 /* Make sure we check our delay slots for validity. */
39bec121 5310 if (insn.tm->flags & FL_DELAY)
9a736b6b
NC
5311 {
5312 delay_slots = 2;
5313 /* FIXME -- warn if delay_slots != 0 at EOF. */
5314 }
39bec121
TW
5315 }
5316}
5317
5318/* Do a final adjustment on the symbol table; in this case, make sure we have
d0313fb7 5319 a ".file" symbol. */
9a736b6b 5320
39bec121
TW
5321void
5322tic54x_adjust_symtab ()
5323{
5324 if (symbol_rootP == NULL
5325 || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
5326 {
5327 char *filename;
5328 unsigned lineno;
5329 as_where (&filename, &lineno);
5519f6ea 5330 c_dot_file_symbol (filename, 0);
39bec121
TW
5331 }
5332}
5333
5334/* In order to get gas to ignore any | chars at the start of a line,
1aea3bb8 5335 this function returns true if a | is found in a line.
9a736b6b
NC
5336 This lets us process parallel instructions, which span two lines. */
5337
39bec121
TW
5338int
5339tic54x_unrecognized_line (int c)
5340{
5341 return c == PARALLEL_SEPARATOR;
5342}
5343
5344/* Watch for local labels of the form $[0-9] and [_a-zA-Z][_a-zA-Z0-9]*?
5345 Encode their names so that only we see them and can map them to the
5346 appropriate places.
5347 FIXME -- obviously this isn't done yet. These locals still show up in the
d0313fb7 5348 symbol table. */
39bec121 5349void
d0313fb7
NC
5350tic54x_define_label (sym)
5351 symbolS *sym;
39bec121 5352{
d0313fb7 5353 /* Just in case we need this later; note that this is not necessarily the
1aea3bb8 5354 same thing as line_label...
39bec121
TW
5355 When aligning or assigning labels to fields, sometimes the label is
5356 assigned other than the address at which the label appears.
5357 FIXME -- is this really needed? I think all the proper label assignment
d0313fb7 5358 is done in tic54x_cons. */
39bec121
TW
5359 last_label_seen = sym;
5360}
5361
d0313fb7 5362/* Try to parse something that normal parsing failed at. */
9a736b6b 5363
39bec121
TW
5364symbolS *
5365tic54x_undefined_symbol (name)
5366 char *name;
5367{
5368 symbol *sym;
5369
d0313fb7 5370 /* Not sure how to handle predefined symbols. */
1aea3bb8
NC
5371 if ((sym = (symbol *) hash_find (cc_hash, name)) != NULL ||
5372 (sym = (symbol *) hash_find (cc2_hash, name)) != NULL ||
5373 (sym = (symbol *) hash_find (cc3_hash, name)) != NULL ||
5374 (sym = (symbol *) hash_find (misc_symbol_hash, name)) != NULL ||
5375 (sym = (symbol *) hash_find (sbit_hash, name)) != NULL)
39bec121 5376 {
1aea3bb8 5377 return symbol_new (name, reg_section,
9a736b6b
NC
5378 (valueT) sym->value,
5379 &zero_address_frag);
39bec121
TW
5380 }
5381
1aea3bb8
NC
5382 if ((sym = (symbol *) hash_find (reg_hash, name)) != NULL ||
5383 (sym = (symbol *) hash_find (mmreg_hash, name)) != NULL ||
39bec121
TW
5384 !strcasecmp (name, "a") || !strcasecmp (name, "b"))
5385 {
1aea3bb8 5386 return symbol_new (name, reg_section,
9a736b6b
NC
5387 (valueT) sym ? sym->value : 0,
5388 &zero_address_frag);
39bec121
TW
5389 }
5390
5391 return NULL;
5392}
5393
d0313fb7
NC
5394/* Parse a name in an expression before the expression parser takes a stab at
5395 it. */
9a736b6b 5396
39bec121
TW
5397int
5398tic54x_parse_name (name, exp)
5399 char *name ATTRIBUTE_UNUSED;
5400 expressionS *exp ATTRIBUTE_UNUSED;
5401{
39bec121
TW
5402 return 0;
5403}
5404
5405char *
5406md_atof (type, literalP, sizeP)
5407 int type;
5408 char *literalP;
5409 int *sizeP;
5410{
5411#define MAX_LITTLENUMS 2
5412 LITTLENUM_TYPE words[MAX_LITTLENUMS];
5413 LITTLENUM_TYPE *word;
9a736b6b 5414 /* Only one precision on the c54x. */
39bec121
TW
5415 int prec = 2;
5416 char *t = atof_ieee (input_line_pointer, type, words);
5417 if (t)
5418 input_line_pointer = t;
5419 *sizeP = 4;
5420
1aea3bb8
NC
5421 /* Target data is little-endian, but floats are stored
5422 big-"word"ian. ugh. */
39bec121
TW
5423 for (word = words; prec--;)
5424 {
1aea3bb8 5425 md_number_to_chars (literalP, (long) (*word++), sizeof (LITTLENUM_TYPE));
39bec121
TW
5426 literalP += sizeof (LITTLENUM_TYPE);
5427 }
5428
5429 return 0;
5430}
5431
5432arelent *
5433tc_gen_reloc (section, fixP)
5434 asection *section;
5435 fixS *fixP;
5436{
5437 arelent *rel;
5438 bfd_reloc_code_real_type code = fixP->fx_r_type;
5439 asymbol *sym = symbol_get_bfdsym (fixP->fx_addsy);
5440
5441 rel = (arelent *) xmalloc (sizeof (arelent));
1aea3bb8 5442 rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
39bec121 5443 *rel->sym_ptr_ptr = sym;
9a736b6b 5444 /* We assume that all rel->address are host byte offsets. */
39bec121
TW
5445 rel->address = fixP->fx_frag->fr_address + fixP->fx_where;
5446 rel->address /= OCTETS_PER_BYTE;
5447 rel->howto = bfd_reloc_type_lookup (stdoutput, code);
5448 if (!strcmp (sym->name, section->name))
5449 rel->howto += HOWTO_BANK;
5450
5451 if (!rel->howto)
5452 {
5453 const char *name = S_GET_NAME (fixP->fx_addsy);
5454 if (name == NULL)
5455 name = "<unknown>";
1aea3bb8 5456 as_fatal ("Cannot generate relocation type for symbol %s, code %s",
9a736b6b 5457 name, bfd_get_reloc_code_name (code));
39bec121
TW
5458 return NULL;
5459 }
5460 return rel;
5461}
5462
d0313fb7 5463/* Handle cons expressions. */
9a736b6b 5464
39bec121 5465void
f1e7a2c9
NC
5466tic54x_cons_fix_new (frag, where, octets, exp)
5467 fragS *frag;
5468 int where;
5469 int octets;
5470 expressionS *exp;
39bec121
TW
5471{
5472 bfd_reloc_code_real_type r;
f1e7a2c9 5473
39bec121
TW
5474 switch (octets)
5475 {
5476 default:
5477 as_bad (_("Unsupported relocation size %d"), octets);
5478 r = BFD_RELOC_TIC54X_16_OF_23;
5479 break;
5480 case 2:
5481 r = BFD_RELOC_TIC54X_16_OF_23;
5482 break;
5483 case 4:
d0313fb7 5484 /* TI assembler always uses this, regardless of addressing mode. */
39bec121 5485 if (emitting_long)
9a736b6b 5486 r = BFD_RELOC_TIC54X_23;
39bec121 5487 else
9a736b6b
NC
5488 /* We never want to directly generate this; this is provided for
5489 stabs support only. */
5490 r = BFD_RELOC_32;
39bec121
TW
5491 break;
5492 }
5493 fix_new_exp (frag, where, octets, exp, 0, r);
5494}
5495
1aea3bb8 5496/* Attempt to simplify or even eliminate a fixup.
39bec121
TW
5497 To indicate that a fixup has been eliminated, set fixP->fx_done.
5498
d0313fb7 5499 If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry. */
9a736b6b 5500
94f592af
NC
5501void
5502md_apply_fix3 (fixP, valP, seg)
39bec121 5503 fixS *fixP;
94f592af
NC
5504 valueT * valP;
5505 segT seg ATTRIBUTE_UNUSED;
39bec121
TW
5506{
5507 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
94f592af 5508 valueT val = * valP;
39bec121
TW
5509
5510 switch (fixP->fx_r_type)
5511 {
5512 default:
5513 as_fatal ("Bad relocation type: 0x%02x", fixP->fx_r_type);
94f592af 5514 return;
39bec121
TW
5515 case BFD_RELOC_TIC54X_MS7_OF_23:
5516 val = (val >> 16) & 0x7F;
d0313fb7 5517 /* Fall through. */
39bec121
TW
5518 case BFD_RELOC_TIC54X_16_OF_23:
5519 case BFD_RELOC_16:
5520 bfd_put_16 (stdoutput, val, buf);
d0313fb7 5521 /* Indicate what we're actually writing, so that we don't get warnings
9a736b6b 5522 about exceeding available space. */
39bec121
TW
5523 *valP = val & 0xFFFF;
5524 break;
5525 case BFD_RELOC_TIC54X_PARTLS7:
5526 bfd_put_16 (stdoutput,
9a736b6b
NC
5527 (bfd_get_16 (stdoutput, buf) & 0xFF80) | (val & 0x7F),
5528 buf);
d0313fb7 5529 /* Indicate what we're actually writing, so that we don't get warnings
9a736b6b 5530 about exceeding available space. */
39bec121
TW
5531 *valP = val & 0x7F;
5532 break;
5533 case BFD_RELOC_TIC54X_PARTMS9:
5534 /* TI assembler doesn't shift its encoding for relocatable files, and is
9a736b6b 5535 thus incompatible with this implementation's relocatable files. */
1aea3bb8 5536 bfd_put_16 (stdoutput,
9a736b6b
NC
5537 (bfd_get_16 (stdoutput, buf) & 0xFE00) | (val >> 7),
5538 buf);
39bec121
TW
5539 break;
5540 case BFD_RELOC_32:
5541 case BFD_RELOC_TIC54X_23:
5542 bfd_put_32 (stdoutput,
9a736b6b
NC
5543 (bfd_get_32 (stdoutput, buf) & 0xFF800000) | val,
5544 buf);
39bec121
TW
5545 break;
5546 }
5547
94f592af
NC
5548 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
5549 fixP->fx_done = 1;
39bec121
TW
5550}
5551
1aea3bb8 5552/* This is our chance to record section alignment
d0313fb7 5553 don't need to do anything here, since BFD does the proper encoding. */
9a736b6b 5554
39bec121
TW
5555valueT
5556md_section_align (segment, section_size)
5557 segT segment ATTRIBUTE_UNUSED;
5558 valueT section_size;
5559{
5560 return section_size;
5561}
5562
5563long
5564md_pcrel_from (fixP)
5565 fixS *fixP ATTRIBUTE_UNUSED;
5566{
5567 return 0;
5568}
5569
5570#if defined OBJ_COFF
5571
5572short
5573tc_coff_fix2rtype (fixP)
5574 fixS *fixP;
5575{
5576 return (fixP->fx_r_type);
5577}
5578
9a736b6b
NC
5579#endif /* OBJ_COFF */
5580
5581/* Mostly little-endian, but longwords (4 octets) get MS word stored
5582 first. */
39bec121 5583
39bec121
TW
5584void
5585tic54x_number_to_chars (buf, val, n)
9a736b6b
NC
5586 char *buf;
5587 valueT val;
5588 int n;
39bec121
TW
5589{
5590 if (n != 4)
9a736b6b 5591 number_to_chars_littleendian (buf, val, n);
39bec121
TW
5592 else
5593 {
1aea3bb8
NC
5594 number_to_chars_littleendian (buf , val >> 16 , 2);
5595 number_to_chars_littleendian (buf + 2, val & 0xFFFF, 2);
39bec121
TW
5596 }
5597}
5598
1aea3bb8 5599int
39bec121 5600tic54x_estimate_size_before_relax (frag, seg)
9a736b6b
NC
5601 fragS *frag ATTRIBUTE_UNUSED;
5602 segT seg ATTRIBUTE_UNUSED;
39bec121
TW
5603{
5604 return 0;
5605}
5606
d0313fb7
NC
5607/* We use this to handle bit allocations which we couldn't handle before due
5608 to symbols being in different frags. return number of octets added. */
9a736b6b 5609
1aea3bb8 5610int
39bec121 5611tic54x_relax_frag (frag, stretch)
1aea3bb8
NC
5612 fragS *frag;
5613 long stretch ATTRIBUTE_UNUSED;
39bec121
TW
5614{
5615 symbolS *sym = frag->fr_symbol;
5616 int growth = 0;
5617 int i;
5618
5619 if (sym != NULL)
5620 {
1aea3bb8 5621 struct bit_info *bi = (struct bit_info *) frag->fr_opcode;
39bec121
TW
5622 int bit_offset = frag_bit_offset (frag_prev (frag, bi->seg), bi->seg);
5623 int size = S_GET_VALUE (sym);
5624 fragS *prev_frag = bit_offset_frag (frag_prev (frag, bi->seg), bi->seg);
5625 int available = 16 - bit_offset;
5626
5627 if (symbol_get_frag (sym) != &zero_address_frag
9a736b6b
NC
5628 || S_IS_COMMON (sym)
5629 || !S_IS_DEFINED (sym))
5630 as_bad_where (frag->fr_file, frag->fr_line,
5631 _("non-absolute value used with .space/.bes"));
39bec121
TW
5632
5633 if (size < 0)
9a736b6b
NC
5634 {
5635 as_warn (_("negative value ignored in %s"),
5636 bi->type == TYPE_SPACE ? ".space" :
5637 bi->type == TYPE_BES ? ".bes" : ".field");
5638 growth = 0;
5639 frag->tc_frag_data = frag->fr_fix = 0;
5640 return 0;
5641 }
39bec121
TW
5642
5643 if (bi->type == TYPE_FIELD)
9a736b6b
NC
5644 {
5645 /* Bit fields of 16 or larger will have already been handled. */
5646 if (bit_offset != 0 && available >= size)
5647 {
5648 char *p = prev_frag->fr_literal;
f1e7a2c9 5649
9a736b6b
NC
5650 valueT value = bi->value;
5651 value <<= available - size;
5652 value |= ((unsigned short) p[1] << 8) | p[0];
5653 md_number_to_chars (p, value, 2);
5654 if ((prev_frag->tc_frag_data += size) == 16)
5655 prev_frag->tc_frag_data = 0;
5656 if (bi->sym)
5657 symbol_set_frag (bi->sym, prev_frag);
5658 /* This frag is no longer used. */
5659 growth = -frag->fr_fix;
5660 frag->fr_fix = 0;
5661 frag->tc_frag_data = 0;
5662 }
5663 else
5664 {
5665 char *p = frag->fr_literal;
f1e7a2c9 5666
9a736b6b
NC
5667 valueT value = bi->value << (16 - size);
5668 md_number_to_chars (p, value, 2);
5669 if ((frag->tc_frag_data = size) == 16)
5670 frag->tc_frag_data = 0;
5671 growth = 0;
5672 }
5673 }
39bec121 5674 else
9a736b6b
NC
5675 {
5676 if (bit_offset != 0 && bit_offset < 16)
5677 {
5678 if (available >= size)
5679 {
5680 if ((prev_frag->tc_frag_data += size) == 16)
5681 prev_frag->tc_frag_data = 0;
5682 if (bi->sym)
5683 symbol_set_frag (bi->sym, prev_frag);
5684 /* This frag is no longer used. */
5685 growth = -frag->fr_fix;
5686 frag->fr_fix = 0;
5687 frag->tc_frag_data = 0;
5688 goto getout;
5689 }
5690 if (bi->type == TYPE_SPACE && bi->sym)
5691 symbol_set_frag (bi->sym, prev_frag);
5692 size -= available;
5693 }
5694 growth = (size + 15) / 16 * OCTETS_PER_BYTE - frag->fr_fix;
5695 for (i = 0; i < growth; i++)
5696 frag->fr_literal[i] = 0;
5697 frag->fr_fix = growth;
5698 frag->tc_frag_data = size % 16;
5699 /* Make sure any BES label points to the LAST word allocated. */
5700 if (bi->type == TYPE_BES && bi->sym)
5701 S_SET_VALUE (bi->sym, frag->fr_fix / OCTETS_PER_BYTE - 1);
5702 }
39bec121
TW
5703 getout:
5704 frag->fr_symbol = 0;
5705 frag->fr_opcode = 0;
1aea3bb8 5706 free ((void *) bi);
39bec121
TW
5707 }
5708 return growth;
5709}
5710
5711void
5712tic54x_convert_frag (abfd, seg, frag)
1aea3bb8
NC
5713 bfd *abfd ATTRIBUTE_UNUSED;
5714 segT seg ATTRIBUTE_UNUSED;
5715 fragS *frag;
39bec121 5716{
d0313fb7 5717 /* Offset is in bytes. */
1aea3bb8 5718 frag->fr_offset = (frag->fr_next->fr_address
9a736b6b
NC
5719 - frag->fr_address
5720 - frag->fr_fix) / frag->fr_var;
39bec121
TW
5721 if (frag->fr_offset < 0)
5722 {
5723 as_bad_where (frag->fr_file, frag->fr_line,
9a736b6b
NC
5724 _("attempt to .space/.bes backwards? (%ld)"),
5725 (long) frag->fr_offset);
39bec121
TW
5726 }
5727 frag->fr_type = rs_space;
5728}
5729
d0313fb7 5730/* We need to avoid having labels defined for certain directives/pseudo-ops
39bec121
TW
5731 since once the label is defined, it's in the symbol table for good. TI
5732 syntax puts the symbol *before* the pseudo (which is kinda like MRI syntax,
5733 I guess, except I've never seen a definition of MRI syntax).
5734
5735 C is the character that used to be at *REST, which points to the end of the
1aea3bb8 5736 label.
39bec121 5737
d0313fb7 5738 Don't allow labels to start with '.' */
9a736b6b 5739
39bec121
TW
5740int
5741tic54x_start_label (c, rest)
1aea3bb8
NC
5742 int c;
5743 char *rest;
39bec121 5744{
d0313fb7 5745 /* If within .struct/.union, no auto line labels, please. */
39bec121
TW
5746 if (current_stag != NULL)
5747 return 0;
5748
d0313fb7 5749 /* Disallow labels starting with "." */
39bec121
TW
5750 if (c != ':')
5751 {
5752 char *label = rest;
f1e7a2c9 5753
1aea3bb8 5754 while (!is_end_of_line[(int) label[-1]])
9a736b6b 5755 --label;
39bec121 5756 if (*label == '.')
9a736b6b
NC
5757 {
5758 as_bad (_("Invalid label '%s'"), label);
5759 return 0;
5760 }
39bec121
TW
5761 }
5762
1aea3bb8 5763 if (is_end_of_line[(int) c])
39bec121
TW
5764 return 1;
5765
3882b010
L
5766 if (ISSPACE (c))
5767 while (ISSPACE (c = *++rest))
39bec121
TW
5768 ;
5769 if (c == '.')
5770 {
d0313fb7 5771 /* Don't let colon () define a label for any of these... */
3882b010
L
5772 return (strncasecmp (rest, ".tag", 4) != 0 || !ISSPACE (rest[4]))
5773 && (strncasecmp (rest, ".struct", 7) != 0 || !ISSPACE (rest[7]))
5774 && (strncasecmp (rest, ".union", 6) != 0 || !ISSPACE (rest[6]))
5775 && (strncasecmp (rest, ".macro", 6) != 0 || !ISSPACE (rest[6]))
5776 && (strncasecmp (rest, ".set", 4) != 0 || !ISSPACE (rest[4]))
5777 && (strncasecmp (rest, ".equ", 4) != 0 || !ISSPACE (rest[4]));
39bec121
TW
5778 }
5779
5780 return 1;
5781}