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