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