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