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