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