Fix tic54x testsuite failures and Lmem disassembly bugs.
[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 {
d0313fb7 3657 /* Do the fixup later; just store the expression. */
39bec121
TW
3658 insn->opcode[0].r_nchars = 1;
3659 insn->opcode[0].r_type = BFD_RELOC_TIC54X_PARTLS7;
3660 insn->opcode[0].unresolved = 1;
3661 }
3662
3663 return 1;
3664}
3665
3666static int
6e917903 3667encode_indirect (tic54x_insn *insn, struct opstruct *operand)
39bec121
TW
3668{
3669 int arf;
3670 int mod;
3671
3672 if (insn->is_lkaddr)
3673 {
d0313fb7 3674 /* lk addresses always go in the second insn word. */
3882b010 3675 mod = ((TOUPPER (operand->buf[1]) == 'A') ? 12 :
9a736b6b
NC
3676 (operand->buf[1] == '(') ? 15 :
3677 (strchr (operand->buf, '%') != NULL) ? 14 : 13);
39bec121 3678 arf = ((mod == 12) ? operand->buf[3] - '0' :
9a736b6b 3679 (mod == 15) ? 0 : operand->buf[4] - '0');
1aea3bb8 3680
39bec121
TW
3681 insn->opcode[1].addr_expr = operand->exp;
3682
3683 if (operand->exp.X_op == O_constant)
9a736b6b 3684 insn->opcode[1].word = operand->exp.X_add_number;
39bec121 3685 else
9a736b6b
NC
3686 {
3687 insn->opcode[1].word = 0;
3688 insn->opcode[1].r_nchars = 2;
3689 insn->opcode[1].r_type = BFD_RELOC_TIC54X_16_OF_23;
3690 insn->opcode[1].unresolved = 1;
3691 }
39bec121
TW
3692 }
3693 else if (strncasecmp (operand->buf, "*sp (", 4) == 0)
3694 {
d0313fb7 3695 /* Stack offsets look the same as 7-bit direct addressing. */
39bec121
TW
3696 return encode_address (insn, operand);
3697 }
3698 else
3699 {
3882b010 3700 arf = (TOUPPER (operand->buf[1]) == 'A' ?
9a736b6b 3701 operand->buf[3] : operand->buf[4]) - '0';
1aea3bb8
NC
3702
3703 if (operand->buf[1] == '+')
9a736b6b
NC
3704 {
3705 mod = 3; /* *+ARx */
3706 if (insn->tm->flags & FL_SMR)
3707 as_warn (_("Address mode *+ARx is write-only. "
3708 "Results of reading are undefined."));
3709 }
1aea3bb8 3710 else if (operand->buf[4] == '\0')
9a736b6b 3711 mod = 0; /* *ARx */
39bec121 3712 else if (operand->buf[5] == '\0')
9a736b6b 3713 mod = (operand->buf[4] == '-' ? 1 : 2); /* *ARx+ / *ARx- */
39bec121 3714 else if (operand->buf[6] == '\0')
9a736b6b
NC
3715 {
3716 if (operand->buf[5] == '0')
3717 mod = (operand->buf[4] == '-' ? 5 : 6); /* *ARx+0 / *ARx-0 */
3718 else
3719 mod = (operand->buf[4] == '-' ? 8 : 10);/* *ARx+% / *ARx-% */
3720 }
3882b010 3721 else if (TOUPPER (operand->buf[6]) == 'B')
9a736b6b 3722 mod = (operand->buf[4] == '-' ? 4 : 7); /* ARx+0B / *ARx-0B */
3882b010 3723 else if (TOUPPER (operand->buf[6]) == '%')
9a736b6b 3724 mod = (operand->buf[4] == '-' ? 9 : 11); /* ARx+0% / *ARx - 0% */
39bec121 3725 else
9a736b6b
NC
3726 {
3727 as_bad (_("Unrecognized indirect address format \"%s\""),
3728 operand->buf);
3729 return 0;
3730 }
1aea3bb8 3731 }
39bec121 3732
1aea3bb8 3733 insn->opcode[0].word |= 0x80 | (mod << 3) | arf;
39bec121
TW
3734
3735 return 1;
3736}
3737
3738static int
6e917903
TW
3739encode_integer (tic54x_insn *insn,
3740 struct opstruct *operand,
3741 int which, int min, int max, unsigned short mask)
39bec121
TW
3742{
3743 long parse, integer;
3744
3745 insn->opcode[which].addr_expr = operand->exp;
3746
3747 if (operand->exp.X_op == O_constant)
3748 {
3749 parse = operand->exp.X_add_number;
d0313fb7 3750 /* Hack -- fixup for 16-bit hex quantities that get converted positive
9a736b6b 3751 instead of negative. */
39bec121 3752 if ((parse & 0x8000) && min == -32768 && max == 32767)
9a736b6b 3753 integer = (short) parse;
39bec121 3754 else
9a736b6b 3755 integer = parse;
39bec121
TW
3756
3757 if (integer >= min && integer <= max)
9a736b6b
NC
3758 {
3759 insn->opcode[which].word |= (integer & mask);
3760 return 1;
3761 }
1aea3bb8 3762 as_bad (_("Operand '%s' out of range (%d <= x <= %d)"),
9a736b6b 3763 operand->buf, min, max);
39bec121
TW
3764 }
3765 else
3766 {
3767 if (insn->opcode[which].addr_expr.X_op == O_constant)
9a736b6b
NC
3768 {
3769 insn->opcode[which].word |=
3770 insn->opcode[which].addr_expr.X_add_number & mask;
3771 }
39bec121 3772 else
9a736b6b
NC
3773 {
3774 /* Do the fixup later; just store the expression. */
3775 bfd_reloc_code_real_type rtype =
3776 (mask == 0x1FF ? BFD_RELOC_TIC54X_PARTMS9 :
3777 mask == 0xFFFF ? BFD_RELOC_TIC54X_16_OF_23 :
3778 mask == 0x7F ? BFD_RELOC_TIC54X_PARTLS7 : BFD_RELOC_8);
3779 int size = (mask == 0x1FF || mask == 0xFFFF) ? 2 : 1;
3780
3781 if (rtype == BFD_RELOC_8)
3782 as_bad (_("Error in relocation handling"));
3783
3784 insn->opcode[which].r_nchars = size;
3785 insn->opcode[which].r_type = rtype;
3786 insn->opcode[which].unresolved = 1;
3787 }
39bec121
TW
3788
3789 return 1;
3790 }
3791
3792 return 0;
3793}
3794
3795static int
6e917903 3796encode_condition (tic54x_insn *insn, struct opstruct *operand)
39bec121 3797{
1aea3bb8 3798 symbol *cc = (symbol *) hash_find (cc_hash, operand->buf);
39bec121
TW
3799 if (!cc)
3800 {
3801 as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
3802 return 0;
3803 }
3804#define CC_GROUP 0x40
3805#define CC_ACC 0x08
3806#define CATG_A1 0x07
3807#define CATG_B1 0x30
3808#define CATG_A2 0x30
3809#define CATG_B2 0x0C
3810#define CATG_C2 0x03
d0313fb7 3811 /* Disallow group 1 conditions mixed with group 2 conditions
39bec121 3812 if group 1, allow only one category A and one category B
d0313fb7 3813 if group 2, allow only one each of category A, B, and C. */
39bec121
TW
3814 if (((insn->opcode[0].word & 0xFF) != 0))
3815 {
3816 if ((insn->opcode[0].word & CC_GROUP) != (cc->value & CC_GROUP))
9a736b6b
NC
3817 {
3818 as_bad (_("Condition \"%s\" does not match preceding group"),
3819 operand->buf);
3820 return 0;
3821 }
39bec121 3822 if (insn->opcode[0].word & CC_GROUP)
9a736b6b
NC
3823 {
3824 if ((insn->opcode[0].word & CC_ACC) != (cc->value & CC_ACC))
3825 {
3826 as_bad (_("Condition \"%s\" uses a different accumulator from "
3827 "a preceding condition"),
3828 operand->buf);
3829 return 0;
3830 }
3831 if ((insn->opcode[0].word & CATG_A1) && (cc->value & CATG_A1))
3832 {
3833 as_bad (_("Only one comparison conditional allowed"));
3834 return 0;
3835 }
3836 if ((insn->opcode[0].word & CATG_B1) && (cc->value & CATG_B1))
3837 {
3838 as_bad (_("Only one overflow conditional allowed"));
3839 return 0;
3840 }
3841 }
39bec121 3842 else if (((insn->opcode[0].word & CATG_A2) && (cc->value & CATG_A2)) ||
9a736b6b
NC
3843 ((insn->opcode[0].word & CATG_B2) && (cc->value & CATG_B2)) ||
3844 ((insn->opcode[0].word & CATG_C2) && (cc->value & CATG_C2)))
3845 {
3846 as_bad (_("Duplicate %s conditional"), operand->buf);
3847 return 0;
3848 }
39bec121
TW
3849 }
3850
3851 insn->opcode[0].word |= cc->value;
3852 return 1;
3853}
3854
3855static int
6e917903 3856encode_cc3 (tic54x_insn *insn, struct opstruct *operand)
39bec121 3857{
1aea3bb8 3858 symbol *cc3 = (symbol *) hash_find (cc3_hash, operand->buf);
39bec121
TW
3859 int value = cc3 ? cc3->value : operand->exp.X_add_number << 8;
3860
3861 if ((value & 0x0300) != value)
3862 {
3863 as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
3864 return 0;
3865 }
3866 insn->opcode[0].word |= value;
3867 return 1;
3868}
3869
3870static int
6e917903 3871encode_arx (tic54x_insn *insn, struct opstruct *operand)
39bec121
TW
3872{
3873 int arf = strlen (operand->buf) >= 3 ? operand->buf[2] - '0' : -1;
3874 if (strncasecmp ("ar", operand->buf, 2) || arf < 0 || arf > 7)
3875 {
3876 as_bad (_("Invalid auxiliary register (use AR0-AR7)"));
3877 return 0;
3878 }
3879 insn->opcode[0].word |= arf;
3880 return 1;
3881}
3882
3883static int
6e917903 3884encode_cc2 (tic54x_insn *insn, struct opstruct *operand)
39bec121 3885{
1aea3bb8 3886 symbol *cc2 = (symbol *) hash_find (cc2_hash, operand->buf);
39bec121
TW
3887 if (!cc2)
3888 {
3889 as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
3890 return 0;
3891 }
3892 insn->opcode[0].word |= cc2->value;
3893 return 1;
3894}
3895
3896static int
3897encode_operand (insn, type, operand)
1aea3bb8
NC
3898 tic54x_insn *insn;
3899 enum optype type;
3900 struct opstruct *operand;
39bec121 3901{
6e917903 3902 int ext = (insn->tm->flags & FL_EXT) != 0;
39bec121
TW
3903
3904 if (type == OP_MMR && operand->exp.X_op != O_constant)
3905 {
d0313fb7 3906 /* Disallow long-constant addressing for memory-mapped addressing. */
39bec121 3907 if (insn->is_lkaddr)
9a736b6b
NC
3908 {
3909 as_bad (_("lk addressing modes are invalid for memory-mapped "
3910 "register addressing"));
3911 return 0;
3912 }
39bec121 3913 type = OP_Smem;
d0313fb7 3914 /* Warn about *+ARx when used with MMR operands. */
39bec121 3915 if (strncasecmp (operand->buf, "*+ar", 4) == 0)
9a736b6b
NC
3916 {
3917 as_warn (_("Address mode *+ARx is not allowed in memory-mapped "
3918 "register addressing. Resulting behavior is "
3919 "undefined."));
3920 }
39bec121
TW
3921 }
3922
3923 switch (type)
3924 {
3925 case OP_None:
3926 return 1;
3927 case OP_dmad:
d0313fb7 3928 /* 16-bit immediate value. */
39bec121
TW
3929 return encode_dmad (insn, operand, 0);
3930 case OP_SRC:
3882b010 3931 if (TOUPPER (*operand->buf) == 'B')
9a736b6b
NC
3932 {
3933 insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 9);
3934 if (insn->using_default_dst)
3935 insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
3936 }
39bec121
TW
3937 return 1;
3938 case OP_RND:
d0313fb7 3939 /* Make sure this agrees with with the OP_DST operand. */
3882b010 3940 if (!((TOUPPER (operand->buf[0]) == 'B') ^
9a736b6b
NC
3941 ((insn->opcode[0].word & (1 << 8)) != 0)))
3942 {
3943 as_bad (_("Destination accumulator for each part of this parallel "
3944 "instruction must be different"));
3945 return 0;
3946 }
39bec121
TW
3947 return 1;
3948 case OP_SRC1:
3949 case OP_DST:
3882b010 3950 if (TOUPPER (operand->buf[0]) == 'B')
9a736b6b 3951 insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
39bec121
TW
3952 return 1;
3953 case OP_Xmem:
3954 case OP_Ymem:
1aea3bb8 3955 {
9a736b6b
NC
3956 int mod = (operand->buf[4] == '\0' ? 0 : /* *arx */
3957 operand->buf[4] == '-' ? 1 : /* *arx- */
3958 operand->buf[5] == '\0' ? 2 : 3); /* *arx+, *arx+0% */
1aea3bb8
NC
3959 int arf = operand->buf[3] - '0' - 2;
3960 int code = (mod << 2) | arf;
3961 insn->opcode[0].word |= (code << (type == OP_Xmem ? 4 : 0));
3962 return 1;
3963 }
39bec121
TW
3964 case OP_Lmem:
3965 case OP_Smem:
3966 if (!is_indirect (operand))
9a736b6b
NC
3967 return encode_address (insn, operand);
3968 /* Fall through. */
39bec121
TW
3969 case OP_Sind:
3970 return encode_indirect (insn, operand);
3971 case OP_xpmad_ms7:
3972 return encode_dmad (insn, operand, 2);
3973 case OP_xpmad:
3974 return encode_dmad (insn, operand, 1);
3975 case OP_PA:
3976 case OP_pmad:
3977 return encode_dmad (insn, operand, 0);
3978 case OP_ARX:
3979 return encode_arx (insn, operand);
3980 case OP_MMRX:
3981 case OP_MMRY:
3982 case OP_MMR:
1aea3bb8
NC
3983 {
3984 int value = operand->exp.X_add_number;
3985
3986 if (type == OP_MMR)
3987 insn->opcode[0].word |= value;
3988 else
3989 {
3990 if (value < 16 || value > 24)
3991 {
3992 as_bad (_("Memory mapped register \"%s\" out of range"),
3993 operand->buf);
3994 return 0;
3995 }
3996 if (type == OP_MMRX)
3997 insn->opcode[0].word |= (value - 16) << 4;
3998 else
3999 insn->opcode[0].word |= (value - 16);
4000 }
4001 return 1;
39bec121 4002 }
39bec121
TW
4003 case OP_B:
4004 case OP_A:
4005 return 1;
4006 case OP_SHFT:
1aea3bb8 4007 return encode_integer (insn, operand, ext + insn->is_lkaddr,
9a736b6b 4008 0, 15, 0xF);
39bec121 4009 case OP_SHIFT:
1aea3bb8 4010 return encode_integer (insn, operand, ext + insn->is_lkaddr,
9a736b6b 4011 -16, 15, 0x1F);
39bec121
TW
4012 case OP_lk:
4013 return encode_integer (insn, operand, 1 + insn->is_lkaddr,
9a736b6b 4014 -32768, 32767, 0xFFFF);
39bec121
TW
4015 case OP_CC:
4016 return encode_condition (insn, operand);
4017 case OP_CC2:
4018 return encode_cc2 (insn, operand);
4019 case OP_CC3:
4020 return encode_cc3 (insn, operand);
4021 case OP_BITC:
4022 return encode_integer (insn, operand, 0, 0, 15, 0xF);
4023 case OP_k8:
4024 return encode_integer (insn, operand, 0, -128, 127, 0xFF);
4025 case OP_123:
1aea3bb8
NC
4026 {
4027 int value = operand->exp.X_add_number;
4028 int code;
4029 if (value < 1 || value > 3)
4030 {
4031 as_bad (_("Invalid operand (use 1, 2, or 3)"));
4032 return 0;
4033 }
4034 code = value == 1 ? 0 : value == 2 ? 0x2 : 0x1;
4035 insn->opcode[0].word |= (code << 8);
4036 return 1;
4037 }
39bec121
TW
4038 case OP_031:
4039 return encode_integer (insn, operand, 0, 0, 31, 0x1F);
4040 case OP_k8u:
4041 return encode_integer (insn, operand, 0, 0, 255, 0xFF);
4042 case OP_lku:
1aea3bb8 4043 return encode_integer (insn, operand, 1 + insn->is_lkaddr,
9a736b6b 4044 0, 65535, 0xFFFF);
39bec121 4045 case OP_SBIT:
1aea3bb8
NC
4046 {
4047 symbol *sbit = (symbol *) hash_find (sbit_hash, operand->buf);
4048 int value = is_absolute (operand) ?
4049 operand->exp.X_add_number : (sbit ? sbit->value : -1);
4050 int reg = 0;
4051
4052 if (insn->opcount == 1)
4053 {
4054 if (!sbit)
4055 {
4056 as_bad (_("A status register or status bit name is required"));
4057 return 0;
4058 }
4059 /* Guess the register based on the status bit; "ovb" is the last
4060 status bit defined for st0. */
4061 if (sbit > (symbol *) hash_find (sbit_hash, "ovb"))
4062 reg = 1;
4063 }
4064 if (value == -1)
4065 {
4066 as_bad (_("Unrecognized status bit \"%s\""), operand->buf);
4067 return 0;
4068 }
4069 insn->opcode[0].word |= value;
4070 insn->opcode[0].word |= (reg << 9);
4071 return 1;
4072 }
39bec121
TW
4073 case OP_N:
4074 if (strcasecmp (operand->buf, "st0") == 0
9a736b6b
NC
4075 || strcasecmp (operand->buf, "st1") == 0)
4076 {
4077 insn->opcode[0].word |=
4078 ((unsigned short) (operand->buf[2] - '0')) << 9;
4079 return 1;
4080 }
39bec121 4081 else if (operand->exp.X_op == O_constant
9a736b6b
NC
4082 && (operand->exp.X_add_number == 0
4083 || operand->exp.X_add_number == 1))
4084 {
4085 insn->opcode[0].word |=
4086 ((unsigned short) (operand->exp.X_add_number)) << 9;
4087 return 1;
4088 }
39bec121
TW
4089 as_bad (_("Invalid status register \"%s\""), operand->buf);
4090 return 0;
4091 case OP_k5:
4092 return encode_integer (insn, operand, 0, -16, 15, 0x1F);
4093 case OP_k3:
4094 return encode_integer (insn, operand, 0, 0, 7, 0x7);
4095 case OP_k9:
4096 return encode_integer (insn, operand, 0, 0, 0x1FF, 0x1FF);
4097 case OP_12:
1aea3bb8 4098 if (operand->exp.X_add_number != 1
9a736b6b
NC
4099 && operand->exp.X_add_number != 2)
4100 {
4101 as_bad (_("Operand \"%s\" out of range (use 1 or 2)"), operand->buf);
4102 return 0;
4103 }
39bec121
TW
4104 insn->opcode[0].word |= (operand->exp.X_add_number - 1) << 9;
4105 return 1;
4106 case OP_16:
4107 case OP_T:
4108 case OP_TS:
4109 case OP_ASM:
4110 case OP_TRN:
4111 case OP_DP:
4112 case OP_ARP:
d0313fb7 4113 /* No encoding necessary. */
39bec121
TW
4114 return 1;
4115 default:
4116 return 0;
4117 }
4118
4119 return 1;
4120}
4121
4122static void
6e917903 4123emit_insn (tic54x_insn *insn)
39bec121
TW
4124{
4125 int i;
6e917903
TW
4126 flagword oldflags = bfd_get_section_flags (stdoutput, now_seg);
4127 flagword flags = oldflags | SEC_CODE;
4128
4129 if (! bfd_set_section_flags (stdoutput, now_seg, flags))
4130 as_warn (_("error setting flags for \"%s\": %s"),
4131 bfd_section_name (stdoutput, now_seg),
4132 bfd_errmsg (bfd_get_error ()));
1aea3bb8
NC
4133
4134 for (i = 0; i < insn->words; i++)
39bec121 4135 {
1aea3bb8 4136 int size = (insn->opcode[i].unresolved
9a736b6b 4137 && insn->opcode[i].r_type == BFD_RELOC_TIC54X_23) ? 4 : 2;
39bec121
TW
4138 char *p = frag_more (size);
4139
4140 if (size == 2)
9a736b6b 4141 md_number_to_chars (p, (valueT) insn->opcode[i].word, 2);
39bec121 4142 else
9a736b6b 4143 md_number_to_chars (p, (valueT) insn->opcode[i].word << 16, 4);
1aea3bb8 4144
39bec121 4145 if (insn->opcode[i].unresolved)
9a736b6b
NC
4146 fix_new_exp (frag_now, p - frag_now->fr_literal,
4147 insn->opcode[i].r_nchars, &insn->opcode[i].addr_expr,
4148 false, insn->opcode[i].r_type);
39bec121
TW
4149 }
4150}
4151
1aea3bb8 4152/* Convert the operand strings into appropriate opcode values
d0313fb7 4153 return the total number of words used by the instruction. */
9a736b6b 4154
39bec121 4155static int
6e917903 4156build_insn (tic54x_insn *insn)
39bec121
TW
4157{
4158 int i;
4159
d0313fb7 4160 /* Only non-parallel instructions support lk addressing. */
6e917903 4161 if (!(insn->tm->flags & FL_PAR))
39bec121 4162 {
1aea3bb8 4163 for (i = 0; i < insn->opcount; i++)
9a736b6b
NC
4164 {
4165 if ((OPTYPE (insn->operands[i].type) == OP_Smem
4166 || OPTYPE (insn->operands[i].type) == OP_Lmem
4167 || OPTYPE (insn->operands[i].type) == OP_Sind)
4168 && strchr (insn->operands[i].buf, '(')
4169 /* Don't mistake stack-relative addressing for lk addressing. */
4170 && strncasecmp (insn->operands[i].buf, "*sp (", 4) != 0)
4171 {
4172 insn->is_lkaddr = 1;
4173 insn->lkoperand = i;
4174 break;
4175 }
4176 }
39bec121 4177 }
6e917903 4178 insn->words = insn->tm->words + insn->is_lkaddr;
39bec121 4179
6e917903
TW
4180 insn->opcode[0].word = insn->tm->opcode;
4181 if (insn->tm->flags & FL_EXT)
1aea3bb8 4182 insn->opcode[1 + insn->is_lkaddr].word = insn->tm->opcode2;
39bec121 4183
9a736b6b 4184 for (i = 0; i < insn->opcount; i++)
39bec121
TW
4185 {
4186 enum optype type = insn->operands[i].type;
4187 if (!encode_operand (insn, type, &insn->operands[i]))
9a736b6b 4188 return 0;
39bec121 4189 }
6e917903 4190 if (insn->tm->flags & FL_PAR)
9a736b6b
NC
4191 for (i = 0; i < insn->paropcount; i++)
4192 {
4193 enum optype partype = insn->paroperands[i].type;
4194 if (!encode_operand (insn, partype, &insn->paroperands[i]))
4195 return 0;
4196 }
39bec121
TW
4197
4198 emit_insn (insn);
4199
4200 return insn->words;
4201}
4202
4203static int
6e917903 4204optimize_insn (tic54x_insn *insn)
39bec121 4205{
1aea3bb8 4206 /* Optimize some instructions, helping out the brain-dead programmer. */
39bec121
TW
4207#define is_zero(op) ((op).exp.X_op == O_constant && (op).exp.X_add_number == 0)
4208 if (strcasecmp (insn->tm->name, "add") == 0)
4209 {
9a736b6b
NC
4210 if (insn->opcount > 1
4211 && is_accumulator (&insn->operands[insn->opcount - 2])
4212 && is_accumulator (&insn->operands[insn->opcount - 1])
4213 && strcasecmp (insn->operands[insn->opcount - 2].buf,
4214 insn->operands[insn->opcount - 1].buf) == 0)
4215 {
4216 --insn->opcount;
4217 insn->using_default_dst = 1;
4218 return 1;
4219 }
1aea3bb8 4220
d0313fb7 4221 /* Try to collapse if Xmem and shift count is zero. */
9a736b6b
NC
4222 if ((OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
4223 && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT
4224 && is_zero (insn->operands[1]))
4225 /* Or if Smem, shift is zero or absent, and SRC == DST. */
4226 || (OPTYPE (insn->tm->operand_types[0]) == OP_Smem
4227 && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
4228 && is_type (&insn->operands[1], OP_SHIFT)
4229 && is_zero (insn->operands[1]) && insn->opcount == 3))
4230 {
4231 insn->operands[1] = insn->operands[2];
4232 insn->opcount = 2;
4233 return 1;
4234 }
39bec121
TW
4235 }
4236 else if (strcasecmp (insn->tm->name, "ld") == 0)
4237 {
4238 if (insn->opcount == 3 && insn->operands[0].type != OP_SRC)
9a736b6b
NC
4239 {
4240 if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
4241 || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
4242 && is_zero (insn->operands[1])
4243 && (OPTYPE (insn->tm->operand_types[0]) != OP_lk
4244 || (insn->operands[0].exp.X_op == O_constant
4245 && insn->operands[0].exp.X_add_number <= 255
4246 && insn->operands[0].exp.X_add_number >= 0)))
4247 {
4248 insn->operands[1] = insn->operands[2];
4249 insn->opcount = 2;
4250 return 1;
4251 }
4252 }
4253 }
4254 else if (strcasecmp (insn->tm->name, "sth") == 0
4255 || strcasecmp (insn->tm->name, "stl") == 0)
4256 {
4257 if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
4258 || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
4259 && is_zero (insn->operands[1]))
4260 {
4261 insn->operands[1] = insn->operands[2];
4262 insn->opcount = 2;
4263 return 1;
4264 }
39bec121
TW
4265 }
4266 else if (strcasecmp (insn->tm->name, "sub") == 0)
4267 {
9a736b6b
NC
4268 if (insn->opcount > 1
4269 && is_accumulator (&insn->operands[insn->opcount - 2])
4270 && is_accumulator (&insn->operands[insn->opcount - 1])
4271 && strcasecmp (insn->operands[insn->opcount - 2].buf,
4272 insn->operands[insn->opcount - 1].buf) == 0)
4273 {
4274 --insn->opcount;
4275 insn->using_default_dst = 1;
4276 return 1;
4277 }
4278
4279 if (((OPTYPE (insn->tm->operand_types[0]) == OP_Smem
4280 && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT)
4281 || (OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
4282 && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT))
4283 && is_zero (insn->operands[1])
4284 && insn->opcount == 3)
4285 {
4286 insn->operands[1] = insn->operands[2];
4287 insn->opcount = 2;
4288 return 1;
4289 }
39bec121
TW
4290 }
4291 return 0;
4292}
4293
d0313fb7 4294/* Find a matching template if possible, and get the operand strings. */
9a736b6b 4295
39bec121 4296static int
6e917903 4297tic54x_parse_insn (tic54x_insn *insn, char *line)
39bec121 4298{
1aea3bb8 4299 insn->tm = (template *) hash_find (op_hash, insn->mnemonic);
39bec121
TW
4300 if (!insn->tm)
4301 {
4302 as_bad (_("Unrecognized instruction \"%s\""), insn->mnemonic);
4303 return 0;
4304 }
4305
4306 insn->opcount = get_operands (insn->operands, line);
4307 if (insn->opcount < 0)
1aea3bb8 4308 return 0;
39bec121 4309
d0313fb7 4310 /* Check each variation of operands for this mnemonic. */
39bec121
TW
4311 while (insn->tm->name && strcasecmp (insn->tm->name, insn->mnemonic) == 0)
4312 {
9a736b6b
NC
4313 if (insn->opcount >= insn->tm->minops
4314 && insn->opcount <= insn->tm->maxops
4315 && operands_match (insn, &insn->operands[0], insn->opcount,
4316 insn->tm->operand_types,
4317 insn->tm->minops, insn->tm->maxops))
4318 {
4319 /* SUCCESS! now try some optimizations. */
4320 if (optimize_insn (insn))
4321 {
4322 insn->tm = (template *) hash_find (op_hash,
1aea3bb8 4323 insn->mnemonic);
9a736b6b
NC
4324 continue;
4325 }
39bec121 4326
9a736b6b
NC
4327 return 1;
4328 }
39bec121
TW
4329 ++(insn->tm);
4330 }
1aea3bb8
NC
4331 as_bad (_("Unrecognized operand list '%s' for instruction '%s'"),
4332 line, insn->mnemonic);
39bec121
TW
4333 return 0;
4334}
4335
d0313fb7
NC
4336/* We set this in start_line_hook, 'cause if we do a line replacement, we
4337 won't be able to see the next line. */
39bec121 4338static int parallel_on_next_line_hint = 0;
9a736b6b 4339
39bec121 4340/* See if this is part of a parallel instruction
d0313fb7 4341 Look for a subsequent line starting with "||". */
9a736b6b 4342
39bec121 4343static int
6e917903 4344next_line_shows_parallel (char *next_line)
39bec121 4345{
9a736b6b 4346 /* Look for the second half. */
3882b010 4347 while (ISSPACE (*next_line))
39bec121
TW
4348 ++next_line;
4349
9a736b6b
NC
4350 return (next_line[0] == PARALLEL_SEPARATOR
4351 && next_line[1] == PARALLEL_SEPARATOR);
39bec121
TW
4352}
4353
4354static int
6e917903 4355tic54x_parse_parallel_insn_firstline (tic54x_insn *insn, char *line)
39bec121 4356{
6e917903
TW
4357 insn->tm = (template *) hash_find (parop_hash, insn->mnemonic);
4358 if (!insn->tm)
39bec121 4359 {
1aea3bb8 4360 as_bad (_("Unrecognized parallel instruction \"%s\""),
9a736b6b 4361 insn->mnemonic);
39bec121
TW
4362 return 0;
4363 }
4364
6e917903
TW
4365 while (insn->tm->name && strcasecmp (insn->tm->name,
4366 insn->mnemonic) == 0)
39bec121
TW
4367 {
4368 insn->opcount = get_operands (insn->operands, line);
4369 if (insn->opcount < 0)
9a736b6b
NC
4370 return 0;
4371 if (insn->opcount == 2
4372 && operands_match (insn, &insn->operands[0], insn->opcount,
6e917903 4373 insn->tm->operand_types, 2, 2))
9a736b6b
NC
4374 {
4375 return 1;
4376 }
6e917903 4377 ++(insn->tm);
39bec121 4378 }
d0313fb7 4379 /* Didn't find a matching parallel; try for a normal insn. */
39bec121
TW
4380 return 0;
4381}
4382
d0313fb7 4383/* Parse the second line of a two-line parallel instruction. */
9a736b6b 4384
39bec121 4385static int
6e917903 4386tic54x_parse_parallel_insn_lastline (tic54x_insn *insn, char *line)
39bec121
TW
4387{
4388 int valid_mnemonic = 0;
1aea3bb8 4389
39bec121 4390 insn->paropcount = get_operands (insn->paroperands, line);
6e917903 4391 while (insn->tm->name && strcasecmp (insn->tm->name,
9a736b6b 4392 insn->mnemonic) == 0)
39bec121 4393 {
6e917903 4394 if (strcasecmp (insn->tm->parname, insn->parmnemonic) == 0)
9a736b6b
NC
4395 {
4396 valid_mnemonic = 1;
6e917903
TW
4397 if (insn->paropcount >= insn->tm->minops
4398 && insn->paropcount <= insn->tm->maxops
9a736b6b
NC
4399 && operands_match (insn, insn->paroperands,
4400 insn->paropcount,
6e917903
TW
4401 insn->tm->paroperand_types,
4402 insn->tm->minops, insn->tm->maxops))
9a736b6b
NC
4403 {
4404 return 1;
4405 }
4406 }
6e917903 4407 ++(insn->tm);
39bec121
TW
4408 }
4409 if (valid_mnemonic)
4410 as_bad (_("Invalid operand (s) for parallel instruction \"%s\""),
9a736b6b 4411 insn->parmnemonic);
39bec121
TW
4412 else
4413 as_bad (_("Unrecognized parallel instruction combination \"%s || %s\""),
9a736b6b 4414 insn->mnemonic, insn->parmnemonic);
39bec121
TW
4415
4416 return 0;
4417}
4418
d0313fb7 4419/* If quotes found, return copy of line up to closing quote;
9a736b6b
NC
4420 otherwise up until terminator.
4421 If it's a string, pass as-is; otherwise attempt substitution symbol
d0313fb7 4422 replacement on the value. */
9a736b6b 4423
39bec121
TW
4424static char *
4425subsym_get_arg (char *line, char *terminators, char **str, int nosub)
4426{
4427 char *ptr = line;
4428 char *endp;
4429 int is_string = *line == '"';
3882b010 4430 int is_char = ISDIGIT (*line);
39bec121
TW
4431
4432 if (is_char)
4433 {
3882b010 4434 while (ISDIGIT (*ptr))
9a736b6b 4435 ++ptr;
39bec121
TW
4436 endp = ptr;
4437 *str = xmalloc (ptr - line + 1);
4438 strncpy (*str, line, ptr - line);
4439 (*str)[ptr - line] = 0;
4440 }
4441 else if (is_string)
4442 {
4443 char *savedp = input_line_pointer;
4444 int len;
4445 input_line_pointer = ptr;
4446 *str = demand_copy_C_string (&len);
4447 endp = input_line_pointer;
4448 input_line_pointer = savedp;
4449
d0313fb7 4450 /* Do forced substitutions if requested. */
39bec121 4451 if (!nosub && **str == ':')
9a736b6b 4452 *str = subsym_substitute (*str, 1);
39bec121
TW
4453 }
4454 else
4455 {
4456 char *term = terminators;
4457 char *value = NULL;
4458
4459 while (*ptr && *ptr != *term)
9a736b6b
NC
4460 {
4461 if (!*term)
4462 {
4463 term = terminators;
4464 ++ptr;
4465 }
4466 else
4467 ++term;
4468 }
39bec121
TW
4469 endp = ptr;
4470 *str = xmalloc (ptr - line + 1);
4471 strncpy (*str, line, ptr - line);
4472 (*str)[ptr - line] = 0;
d0313fb7 4473 /* Do simple substitution, if available. */
39bec121 4474 if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
1aea3bb8 4475 *str = value;
39bec121
TW
4476 }
4477
4478 return endp;
4479}
4480
d0313fb7 4481/* Replace the given substitution string.
39bec121
TW
4482 We start at the innermost macro level, so that existing locals remain local
4483 Note: we're treating macro args identically to .var's; I don't know if
d0313fb7 4484 that's compatible w/TI's assembler. */
9a736b6b 4485
39bec121 4486static void
d0313fb7
NC
4487subsym_create_or_replace (name, value)
4488 char *name;
4489 char *value;
39bec121
TW
4490{
4491 int i;
4492
1aea3bb8 4493 for (i = macro_level; i > 0; i--)
39bec121
TW
4494 {
4495 if (hash_find (subsym_hash[i], name))
9a736b6b
NC
4496 {
4497 hash_replace (subsym_hash[i], name, value);
4498 return;
4499 }
39bec121
TW
4500 }
4501 if (hash_find (subsym_hash[0], name))
4502 hash_replace (subsym_hash[0], name, value);
4503 else
4504 hash_insert (subsym_hash[0], name, value);
4505}
4506
9a736b6b
NC
4507/* Look up the substitution string replacement for the given symbol.
4508 Start with the innermost macro substituion table given and work
4509 outwards. */
4510
39bec121 4511static char *
d0313fb7
NC
4512subsym_lookup (name, nest_level)
4513 char *name;
4514 int nest_level;
39bec121
TW
4515{
4516 char *value = hash_find (subsym_hash[nest_level], name);
4517
4518 if (value || nest_level == 0)
4519 return value;
4520
1aea3bb8 4521 return subsym_lookup (name, nest_level - 1);
39bec121
TW
4522}
4523
d0313fb7 4524/* Do substitution-symbol replacement on the given line (recursively).
1aea3bb8 4525 return the argument if no substitution was done
39bec121
TW
4526
4527 Also look for built-in functions ($func (arg)) and local labels.
4528
d0313fb7 4529 If FORCED is set, look for forced substitutions of the form ':SYMBOL:'. */
9a736b6b 4530
39bec121
TW
4531static char *
4532subsym_substitute (char *line, int forced)
4533{
d0313fb7
NC
4534 /* For each apparent symbol, see if it's a substitution symbol, and if so,
4535 replace it in the input. */
9a736b6b
NC
4536 char *replacement; /* current replacement for LINE. */
4537 char *head; /* Start of line. */
4538 char *ptr; /* Current examination point. */
4539 int changed = 0; /* Did we make a substitution? */
4540 int eval_line = 0; /* Is this line a .eval/.asg statement? */
4541 int eval_symbol = 0; /* Are we in the middle of the symbol for
4542 .eval/.asg? */
39bec121
TW
4543 char *eval_end = NULL;
4544 int recurse = 1;
4545 int line_conditional = 0;
4546 char *tmp;
4547
d0313fb7 4548 /* Work with a copy of the input line. */
39bec121
TW
4549 replacement = xmalloc (strlen (line) + 1);
4550 strcpy (replacement, line);
4551
4552 ptr = head = replacement;
4553
d0313fb7 4554 /* Flag lines where we might need to replace a single '=' with two;
39bec121 4555 GAS uses single '=' to assign macro args values, and possibly other
d0313fb7 4556 places, so limit what we replace. */
1aea3bb8
NC
4557 if (strstr (line, ".if")
4558 || strstr (line, ".elseif")
39bec121
TW
4559 || strstr (line, ".break"))
4560 {
4561 line_conditional = 1;
4562 }
4563
d0313fb7
NC
4564 /* Watch out for .eval, so that we avoid doing substitution on the
4565 symbol being assigned a value. */
39bec121 4566 if (strstr (line, ".eval") || strstr (line, ".asg"))
1aea3bb8 4567 eval_line = 1;
39bec121 4568
9a736b6b
NC
4569 /* If it's a macro definition, don't do substitution on the argument
4570 names. */
39bec121
TW
4571 if (strstr (line, ".macro"))
4572 return line;
4573
1aea3bb8 4574 while (!is_end_of_line[(int) *ptr])
39bec121
TW
4575 {
4576 int current_char = *ptr;
4577
d0313fb7 4578 /* Need to update this since LINE may have been modified. */
39bec121 4579 if (eval_line)
1aea3bb8 4580 eval_end = strrchr (ptr, ',');
39bec121 4581
d0313fb7 4582 /* Replace triple double quotes with bounding quote/escapes. */
39bec121 4583 if (current_char == '"' && ptr[1] == '"' && ptr[2] == '"')
9a736b6b
NC
4584 {
4585 ptr[1] = '\\';
4586 tmp = strstr (ptr + 2, "\"\"\"");
4587 if (tmp)
4588 tmp[0] = '\\';
4589 changed = 1;
4590 }
39bec121 4591
d0313fb7 4592 /* Replace a single '=' with a '==';
9a736b6b 4593 for compatibility with older code only. */
1aea3bb8 4594 if (line_conditional && current_char == '=')
9a736b6b
NC
4595 {
4596 if (ptr[1] == '=')
4597 {
4598 ptr += 2;
4599 continue;
4600 }
4601 *ptr++ = '\0';
4602 tmp = xmalloc (strlen (head) + 2 + strlen (ptr) + 1);
4603 sprintf (tmp, "%s==%s", head, ptr);
4604 /* Continue examining after the '=='. */
4605 ptr = tmp + strlen (head) + 2;
4606 free (replacement);
4607 head = replacement = tmp;
4608 changed = 1;
4609 }
39bec121 4610
d0313fb7 4611 /* Flag when we've reached the symbol part of .eval/.asg. */
39bec121 4612 if (eval_line && ptr >= eval_end)
9a736b6b 4613 eval_symbol = 1;
39bec121 4614
d0313fb7 4615 /* For each apparent symbol, see if it's a substitution symbol, and if
9a736b6b 4616 so, replace it in the input. */
39bec121 4617 if ((forced && current_char == ':')
9a736b6b
NC
4618 || (!forced && is_name_beginner (current_char)))
4619 {
4620 char *name; /* Symbol to be replaced. */
4621 char *savedp = input_line_pointer;
4622 int c;
4623 char *value = NULL;
4624 char *tail; /* Rest of line after symbol. */
4625
4626 /* Skip the colon. */
4627 if (forced)
4628 ++ptr;
4629
4630 name = input_line_pointer = ptr;
4631 c = get_symbol_end ();
4632 /* '?' is not normally part of a symbol, but it IS part of a local
4633 label. */
4634 if (c == '?')
4635 {
4636 *input_line_pointer++ = c;
4637 c = *input_line_pointer;
4638 *input_line_pointer = '\0';
4639 }
4640 /* Avoid infinite recursion; if a symbol shows up a second time for
4641 substitution, leave it as is. */
4642 if (hash_find (subsym_recurse_hash, name) == NULL)
4643 value = subsym_lookup (name, macro_level);
4644 else
4645 as_warn (_("%s symbol recursion stopped at "
4646 "second appearance of '%s'"),
4647 forced ? "Forced substitution" : "Substitution", name);
4648 ptr = tail = input_line_pointer;
4649 input_line_pointer = savedp;
4650
4651 /* Check for local labels; replace them with the appropriate
4652 substitution. */
3882b010 4653 if ((*name == '$' && ISDIGIT (name[1]) && name[2] == '\0')
9a736b6b
NC
4654 || name[strlen (name) - 1] == '?')
4655 {
4656 /* Use an existing identifier for that label if, available, or
4657 create a new, unique identifier. */
4658 value = hash_find (local_label_hash[macro_level], name);
4659 if (value == NULL)
4660 {
4661 char digit[11];
4662 char *namecopy = strcpy (xmalloc (strlen (name) + 1), name);
4663 value = strcpy (xmalloc (strlen (name) + sizeof (digit) + 1),
4664 name);
4665 if (*value != '$')
4666 value[strlen (value) - 1] = '\0';
4667 sprintf (digit, ".%d", local_label_id++);
4668 strcat (value, digit);
4669 hash_insert (local_label_hash[macro_level], namecopy, value);
4670 }
4671 /* Indicate where to continue looking for substitutions. */
4672 ptr = tail;
4673 }
4674 /* Check for built-in subsym and math functions. */
4675 else if (value != NULL && *name == '$')
4676 {
4677 subsym_proc_entry *entry = (subsym_proc_entry *) value;
4678 math_proc_entry *math_entry = hash_find (math_hash, name);
4679 char *arg1, *arg2 = NULL;
4680
4681 *ptr = c;
4682 if (entry == NULL)
4683 {
4684 as_bad (_("Unrecognized substitution symbol function"));
4685 break;
4686 }
4687 else if (*ptr != '(')
4688 {
4689 as_bad (_("Missing '(' after substitution symbol function"));
4690 break;
4691 }
4692 ++ptr;
4693 if (math_entry != NULL)
4694 {
4695 float arg1, arg2 = 0;
4696 volatile float fresult;
4697
4698 arg1 = (float) strtod (ptr, &ptr);
4699 if (math_entry->nargs == 2)
4700 {
4701 if (*ptr++ != ',')
4702 {
4703 as_bad (_("Expecting second argument"));
4704 break;
4705 }
4706 arg2 = (float) strtod (ptr, &ptr);
4707 }
4708 fresult = (*math_entry->proc) (arg1, arg2);
4709 value = xmalloc (128);
4710 if (math_entry->int_return)
4711 sprintf (value, "%d", (int) fresult);
4712 else
4713 sprintf (value, "%f", fresult);
4714 if (*ptr++ != ')')
4715 {
4716 as_bad (_("Extra junk in function call, expecting ')'"));
4717 break;
4718 }
4719 /* Don't bother recursing; the replacement isn't a
4720 symbol. */
4721 recurse = 0;
4722 }
4723 else
4724 {
4725 int val;
4726 int arg_type[2] = { *ptr == '"' , 0 };
4727 int ismember = !strcmp (entry->name, "$ismember");
4728 /* Parse one or two args, which must be a substitution
4729 symbol, string or a character-string constant. */
4730 /* For all functions, a string or substitution symbol may be
4731 used, with the following exceptions:
4732 firstch/lastch: 2nd arg must be character constant
4733 ismember: both args must be substitution symbols. */
4734 ptr = subsym_get_arg (ptr, ",)", &arg1, ismember);
4735 if (!arg1)
4736 break;
4737 if (entry->nargs == 2)
4738 {
4739 if (*ptr++ != ',')
4740 {
4741 as_bad (_("Function expects two arguments"));
4742 break;
4743 }
4744 /* Character constants are converted to numerics
4745 by the preprocessor. */
3882b010 4746 arg_type[1] = (ISDIGIT (*ptr)) ? 2 : (*ptr == '"');
9a736b6b
NC
4747 ptr = subsym_get_arg (ptr, ")", &arg2, ismember);
4748 }
4749 /* Args checking. */
4750 if ((!strcmp (entry->name, "$firstch")
4751 || !strcmp (entry->name, "$lastch"))
4752 && arg_type[1] != 2)
4753 {
4754 as_bad (_("Expecting character constant argument"));
4755 break;
4756 }
4757 if (ismember
4758 && (arg_type[0] != 0 || arg_type[1] != 0))
4759 {
4760 as_bad (_("Both arguments must be substitution symbols"));
4761 break;
4762 }
4763 if (*ptr++ != ')')
4764 {
4765 as_bad (_("Extra junk in function call, expecting ')'"));
4766 break;
4767 }
4768 val = (*entry->proc) (arg1, arg2);
4769 value = xmalloc (64);
4770 sprintf (value, "%d", val);
4771 }
4772 /* Fix things up to replace the entire expression, not just the
4773 function name. */
4774 tail = ptr;
4775 c = *tail;
4776 }
4777
4778 if (value != NULL && !eval_symbol)
4779 {
4780 /* Replace the symbol with its string replacement and
4781 continue. Recursively replace VALUE until either no
4782 substitutions are performed, or a substitution that has been
4783 previously made is encountered again.
4784
4785 put the symbol into the recursion hash table so we only
4786 try to replace a symbol once. */
4787 if (recurse)
4788 {
4789 hash_insert (subsym_recurse_hash, name, name);
4790 value = subsym_substitute (value, macro_level > 0);
4791 hash_delete (subsym_recurse_hash, name);
4792 }
4793
4794 /* Temporarily zero-terminate where the symbol started. */
4795 *name = 0;
4796 if (forced)
4797 {
4798 if (c == '(')
4799 {
4800 /* Subscripted substitution symbol -- use just the
4801 indicated portion of the string; the description
4802 kinda indicates that forced substituion is not
4803 supposed to be recursive, but I'm not sure. */
4804 unsigned beg, len = 1; /* default to a single char */
4805 char *newval = strcpy (xmalloc (strlen (value) + 1),
4806 value);
4807
4808 savedp = input_line_pointer;
4809 input_line_pointer = tail + 1;
4810 beg = get_absolute_expression ();
4811 if (beg < 1)
4812 {
4813 as_bad (_("Invalid subscript (use 1 to %d)"),
4814 strlen (value));
4815 break;
4816 }
4817 if (*input_line_pointer == ',')
4818 {
4819 ++input_line_pointer;
4820 len = get_absolute_expression ();
4821 if (beg + len > strlen (value))
4822 {
4823 as_bad (_("Invalid length (use 0 to %d"),
1aea3bb8 4824 strlen (value) - beg);
9a736b6b
NC
4825 break;
4826 }
4827 }
4828 newval += beg - 1;
4829 newval[len] = 0;
4830 tail = input_line_pointer;
4831 if (*tail++ != ')')
4832 {
4833 as_bad (_("Missing ')' in subscripted substitution "
4834 "symbol expression"));
4835 break;
4836 }
4837 c = *tail;
4838 input_line_pointer = savedp;
4839
4840 value = newval;
4841 }
4842 name[-1] = 0;
4843 }
4844 tmp = xmalloc (strlen (head) + strlen (value) +
4845 strlen (tail + 1) + 2);
4846 strcpy (tmp, head);
4847 strcat (tmp, value);
4848 /* Make sure forced substitutions are properly terminated. */
4849 if (forced)
4850 {
4851 if (c != ':')
4852 {
4853 as_bad (_("Missing forced substitution terminator ':'"));
4854 break;
4855 }
4856 ++tail;
39bec121 4857#if 0
9a736b6b
NC
4858 /* Try to replace required whitespace
4859 eliminated by the preprocessor; technically, a forced
4860 substitution could come anywhere, even mid-symbol,
4861 e.g. if x is "0", 'sym:x:end' should result in 'sym0end',
4862 but 'sym:x: end' should result in 'sym0 end'.
4863 FIXME -- this should really be fixed in the preprocessor,
4864 but would require several new states;
4865 KEEP_WHITE_AROUND_COLON does part of the job, but isn't
4866 complete. */
4867 if ((is_part_of_name (tail[1])
4868 && tail[1] != '.'
4869 && tail[1] != '$')
4870 || tail[1] == '\0' || tail[1] == ',' || tail[1] == '"')
4871 ++tail;
4872 else
4873 *tail = ' ';
39bec121 4874#endif
9a736b6b
NC
4875 }
4876 else
4877 /* Restore the character after the symbol end. */
4878 *tail = c;
4879 strcat (tmp, tail);
4880 /* Continue examining after the replacement value. */
4881 ptr = tmp + strlen (head) + strlen (value);
4882 free (replacement);
4883 head = replacement = tmp;
4884 changed = 1;
4885 }
4886 else
4887 *ptr = c;
4888 }
39bec121 4889 else
9a736b6b
NC
4890 {
4891 ++ptr;
4892 }
39bec121
TW
4893 }
4894
4895 if (changed)
4896 return replacement;
4897 else
4898 return line;
4899}
4900
1aea3bb8 4901/* We use this to handle substitution symbols
39bec121
TW
4902 hijack input_line_pointer, replacing it with our substituted string.
4903
4904 .sslist should enable listing the line after replacements are made...
4905
d0313fb7 4906 returns the new buffer limit. */
9a736b6b 4907
39bec121
TW
4908void
4909tic54x_start_line_hook ()
4910{
4911 char *line, *endp;
4912 char *replacement = NULL;
4913
d0313fb7 4914 /* Work with a copy of the input line, including EOL char. */
39bec121 4915 endp = input_line_pointer;
1aea3bb8 4916 while (!is_end_of_line[(int) *endp++])
39bec121
TW
4917 ;
4918 line = xmalloc (endp - input_line_pointer + 1);
4919 strncpy (line, input_line_pointer, endp - input_line_pointer + 1);
4920 line[endp - input_line_pointer] = 0;
4921
d0313fb7 4922 /* Scan ahead for parallel insns. */
39bec121
TW
4923 parallel_on_next_line_hint = next_line_shows_parallel (endp + 1);
4924
d0313fb7 4925 /* If within a macro, first process forced replacements. */
39bec121
TW
4926 if (macro_level > 0)
4927 replacement = subsym_substitute (line, 1);
4928 else
4929 replacement = line;
4930 replacement = subsym_substitute (replacement, 0);
4931
4932 if (replacement != line)
4933 {
4934 char *tmp = replacement;
9a736b6b 4935 char *comment = strchr (replacement, ';');
1aea3bb8 4936 char endc = replacement[strlen (replacement) - 1];
39bec121 4937
d0313fb7 4938 /* Clean up the replacement; we'd prefer to have this done by the
9a736b6b
NC
4939 standard preprocessing equipment (maybe do_scrub_chars?)
4940 but for now, do a quick-and-dirty. */
39bec121 4941 if (comment != NULL)
9a736b6b
NC
4942 {
4943 comment[0] = endc;
4944 comment[1] = 0;
4945 --comment;
4946 }
1aea3bb8 4947 else
9a736b6b 4948 comment = replacement + strlen (replacement) - 1;
39bec121 4949
d0313fb7 4950 /* Trim trailing whitespace. */
3882b010 4951 while (ISSPACE (*comment))
9a736b6b
NC
4952 {
4953 comment[0] = endc;
4954 comment[1] = 0;
4955 --comment;
4956 }
39bec121 4957
d0313fb7 4958 /* Compact leading whitespace. */
3882b010 4959 while (ISSPACE (tmp[0]) && ISSPACE (tmp[1]))
9a736b6b 4960 ++tmp;
39bec121
TW
4961
4962 input_line_pointer = endp;
4963 input_scrub_insert_line (tmp);
4964 free (replacement);
4965 free (line);
d0313fb7 4966 /* Keep track of whether we've done a substitution. */
39bec121
TW
4967 substitution_line = 1;
4968 }
4969 else
4970 {
d0313fb7 4971 /* No change. */
39bec121
TW
4972 free (line);
4973 substitution_line = 0;
4974 }
4975}
4976
4977/* This is the guts of the machine-dependent assembler. STR points to a
4978 machine dependent instruction. This function is supposed to emit
d0313fb7 4979 the frags/bytes it assembles to. */
39bec121
TW
4980void
4981md_assemble (line)
1aea3bb8 4982 char *line;
39bec121
TW
4983{
4984 static int repeat_slot = 0;
9a736b6b 4985 static int delay_slots = 0; /* How many delay slots left to fill? */
39bec121
TW
4986 static int is_parallel = 0;
4987 static tic54x_insn insn;
4988 char *lptr;
4989 char *savedp = input_line_pointer;
4990 int c;
4991
4992 input_line_pointer = line;
4993 c = get_symbol_end ();
4994
4995 if (cpu == VNONE)
4996 cpu = V542;
4997 if (address_mode_needs_set)
4998 {
4999 set_address_mode (amode);
5000 address_mode_needs_set = 0;
5001 }
5002 if (cpu_needs_set)
5003 {
5004 set_cpu (cpu);
5005 cpu_needs_set = 0;
5006 }
5007 assembly_begun = 1;
5008
5009 if (is_parallel)
5010 {
5011 is_parallel = 0;
5012
5013 strcpy (insn.parmnemonic, line);
5014 lptr = input_line_pointer;
5015 *lptr = c;
5016 input_line_pointer = savedp;
5017
5018 if (tic54x_parse_parallel_insn_lastline (&insn, lptr))
9a736b6b
NC
5019 {
5020 int words = build_insn (&insn);
5021
5022 if (delay_slots != 0)
5023 {
5024 if (words > delay_slots)
5025 {
5026 as_bad (_("Instruction does not fit in available delay "
5027 "slots (%d-word insn, %d slots left)"),
1aea3bb8 5028 words, delay_slots);
9a736b6b
NC
5029 delay_slots = 0;
5030 return;
5031 }
5032 delay_slots -= words;
5033 }
5034 }
39bec121
TW
5035 return;
5036 }
5037
5038 memset (&insn, 0, sizeof (insn));
5039 strcpy (insn.mnemonic, line);
5040 lptr = input_line_pointer;
5041 *lptr = c;
5042 input_line_pointer = savedp;
1aea3bb8 5043
39bec121
TW
5044 /* See if this line is part of a parallel instruction; if so, either this
5045 line or the next line will have the "||" specifier preceding the
d0313fb7 5046 mnemonic, and we look for it in the parallel insn hash table. */
39bec121
TW
5047 if (strstr (line, "||") != NULL || parallel_on_next_line_hint)
5048 {
5049 char *tmp = strstr (line, "||");
5050 if (tmp != NULL)
9a736b6b 5051 *tmp = '\0';
39bec121
TW
5052
5053 if (tic54x_parse_parallel_insn_firstline (&insn, lptr))
9a736b6b
NC
5054 {
5055 is_parallel = 1;
5056 /* If the parallel part is on the same line, process it now,
5057 otherwise let the assembler pick up the next line for us. */
5058 if (tmp != NULL)
5059 {
3882b010 5060 while (ISSPACE (tmp[2]))
9a736b6b
NC
5061 ++tmp;
5062 md_assemble (tmp + 2);
5063 }
5064 }
39bec121 5065 else
9a736b6b
NC
5066 {
5067 as_bad (_("Unrecognized parallel instruction '%s'"), line);
5068 }
39bec121
TW
5069 return;
5070 }
5071
5072 if (tic54x_parse_insn (&insn, lptr))
5073 {
5074 int words;
5075
1aea3bb8 5076 if ((insn.tm->flags & FL_LP)
9a736b6b
NC
5077 && cpu != V545LP && cpu != V546LP)
5078 {
5079 as_bad (_("Instruction '%s' requires an LP cpu version"),
5080 insn.tm->name);
5081 return;
5082 }
1aea3bb8 5083 if ((insn.tm->flags & FL_FAR)
9a736b6b
NC
5084 && amode != far_mode)
5085 {
5086 as_bad (_("Instruction '%s' requires far mode addressing"),
5087 insn.tm->name);
5088 return;
5089 }
39bec121
TW
5090
5091 words = build_insn (&insn);
5092
d0313fb7 5093 /* Is this instruction in a delay slot? */
39bec121 5094 if (delay_slots)
9a736b6b
NC
5095 {
5096 if (words > delay_slots)
5097 {
5098 as_warn (_("Instruction does not fit in available delay "
5099 "slots (%d-word insn, %d slots left). "
5100 "Resulting behavior is undefined."),
5101 words, delay_slots);
5102 delay_slots = 0;
5103 return;
5104 }
5105 /* Branches in delay slots are not allowed. */
5106 if (insn.tm->flags & FL_BMASK)
5107 {
5108 as_warn (_("Instructions which cause PC discontinuity are not "
5109 "allowed in a delay slot. "
5110 "Resulting behavior is undefined."));
5111 }
5112 delay_slots -= words;
5113 }
5114
5115 /* Is this instruction the target of a repeat? */
39bec121 5116 if (repeat_slot)
9a736b6b
NC
5117 {
5118 if (insn.tm->flags & FL_NR)
5119 as_warn (_("'%s' is not repeatable. "
5120 "Resulting behavior is undefined."),
5121 insn.tm->name);
5122 else if (insn.is_lkaddr)
5123 as_warn (_("Instructions using long offset modifiers or absolute "
5124 "addresses are not repeatable. "
5125 "Resulting behavior is undefined."));
5126 repeat_slot = 0;
5127 }
1aea3bb8 5128
d0313fb7 5129 /* Make sure we check the target of a repeat instruction. */
39bec121 5130 if (insn.tm->flags & B_REPEAT)
9a736b6b
NC
5131 {
5132 repeat_slot = 1;
5133 /* FIXME -- warn if repeat_slot == 1 at EOF. */
5134 }
d0313fb7 5135 /* Make sure we check our delay slots for validity. */
39bec121 5136 if (insn.tm->flags & FL_DELAY)
9a736b6b
NC
5137 {
5138 delay_slots = 2;
5139 /* FIXME -- warn if delay_slots != 0 at EOF. */
5140 }
39bec121
TW
5141 }
5142}
5143
5144/* Do a final adjustment on the symbol table; in this case, make sure we have
d0313fb7 5145 a ".file" symbol. */
9a736b6b 5146
39bec121
TW
5147void
5148tic54x_adjust_symtab ()
5149{
5150 if (symbol_rootP == NULL
5151 || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
5152 {
5153 char *filename;
5154 unsigned lineno;
5155 as_where (&filename, &lineno);
5156 c_dot_file_symbol (filename);
5157 }
5158}
5159
5160/* In order to get gas to ignore any | chars at the start of a line,
1aea3bb8 5161 this function returns true if a | is found in a line.
9a736b6b
NC
5162 This lets us process parallel instructions, which span two lines. */
5163
39bec121
TW
5164int
5165tic54x_unrecognized_line (int c)
5166{
5167 return c == PARALLEL_SEPARATOR;
5168}
5169
5170/* Watch for local labels of the form $[0-9] and [_a-zA-Z][_a-zA-Z0-9]*?
5171 Encode their names so that only we see them and can map them to the
5172 appropriate places.
5173 FIXME -- obviously this isn't done yet. These locals still show up in the
d0313fb7 5174 symbol table. */
39bec121 5175void
d0313fb7
NC
5176tic54x_define_label (sym)
5177 symbolS *sym;
39bec121 5178{
1aea3bb8
NC
5179#if 0
5180 static int local_label_count = 0;
5181 const char *name = S_GET_NAME (sym);
5182#endif
39bec121 5183
d0313fb7 5184 /* Just in case we need this later; note that this is not necessarily the
1aea3bb8 5185 same thing as line_label...
39bec121
TW
5186 When aligning or assigning labels to fields, sometimes the label is
5187 assigned other than the address at which the label appears.
5188 FIXME -- is this really needed? I think all the proper label assignment
d0313fb7 5189 is done in tic54x_cons. */
39bec121
TW
5190 last_label_seen = sym;
5191}
5192
d0313fb7 5193/* Try to parse something that normal parsing failed at. */
9a736b6b 5194
39bec121
TW
5195symbolS *
5196tic54x_undefined_symbol (name)
5197 char *name;
5198{
5199 symbol *sym;
5200
d0313fb7 5201 /* Not sure how to handle predefined symbols. */
1aea3bb8
NC
5202 if ((sym = (symbol *) hash_find (cc_hash, name)) != NULL ||
5203 (sym = (symbol *) hash_find (cc2_hash, name)) != NULL ||
5204 (sym = (symbol *) hash_find (cc3_hash, name)) != NULL ||
5205 (sym = (symbol *) hash_find (misc_symbol_hash, name)) != NULL ||
5206 (sym = (symbol *) hash_find (sbit_hash, name)) != NULL)
39bec121 5207 {
1aea3bb8 5208 return symbol_new (name, reg_section,
9a736b6b
NC
5209 (valueT) sym->value,
5210 &zero_address_frag);
39bec121
TW
5211 }
5212
1aea3bb8
NC
5213 if ((sym = (symbol *) hash_find (reg_hash, name)) != NULL ||
5214 (sym = (symbol *) hash_find (mmreg_hash, name)) != NULL ||
39bec121
TW
5215 !strcasecmp (name, "a") || !strcasecmp (name, "b"))
5216 {
1aea3bb8 5217 return symbol_new (name, reg_section,
9a736b6b
NC
5218 (valueT) sym ? sym->value : 0,
5219 &zero_address_frag);
39bec121
TW
5220 }
5221
5222 return NULL;
5223}
5224
d0313fb7
NC
5225/* Parse a name in an expression before the expression parser takes a stab at
5226 it. */
9a736b6b 5227
39bec121
TW
5228int
5229tic54x_parse_name (name, exp)
5230 char *name ATTRIBUTE_UNUSED;
5231 expressionS *exp ATTRIBUTE_UNUSED;
5232{
5233#if 0
1aea3bb8
NC
5234 symbol *sym = (symbol *) hash_find (mmreg_hash, name);
5235
d0313fb7 5236 /* If it's a MMREG, replace it with its constant value. */
39bec121
TW
5237 if (sym)
5238 {
5239 exp->X_op = O_constant;
5240 exp->X_add_number = sym->value;
5241 return 1;
5242 }
5243#endif
5244 return 0;
5245}
5246
5247char *
5248md_atof (type, literalP, sizeP)
5249 int type;
5250 char *literalP;
5251 int *sizeP;
5252{
5253#define MAX_LITTLENUMS 2
5254 LITTLENUM_TYPE words[MAX_LITTLENUMS];
5255 LITTLENUM_TYPE *word;
9a736b6b 5256 /* Only one precision on the c54x. */
39bec121
TW
5257 int prec = 2;
5258 char *t = atof_ieee (input_line_pointer, type, words);
5259 if (t)
5260 input_line_pointer = t;
5261 *sizeP = 4;
5262
1aea3bb8
NC
5263 /* Target data is little-endian, but floats are stored
5264 big-"word"ian. ugh. */
39bec121
TW
5265 for (word = words; prec--;)
5266 {
1aea3bb8 5267 md_number_to_chars (literalP, (long) (*word++), sizeof (LITTLENUM_TYPE));
39bec121
TW
5268 literalP += sizeof (LITTLENUM_TYPE);
5269 }
5270
5271 return 0;
5272}
5273
5274arelent *
5275tc_gen_reloc (section, fixP)
5276 asection *section;
5277 fixS *fixP;
5278{
5279 arelent *rel;
5280 bfd_reloc_code_real_type code = fixP->fx_r_type;
5281 asymbol *sym = symbol_get_bfdsym (fixP->fx_addsy);
5282
5283 rel = (arelent *) xmalloc (sizeof (arelent));
1aea3bb8 5284 rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
39bec121 5285 *rel->sym_ptr_ptr = sym;
9a736b6b 5286 /* We assume that all rel->address are host byte offsets. */
39bec121
TW
5287 rel->address = fixP->fx_frag->fr_address + fixP->fx_where;
5288 rel->address /= OCTETS_PER_BYTE;
5289 rel->howto = bfd_reloc_type_lookup (stdoutput, code);
5290 if (!strcmp (sym->name, section->name))
5291 rel->howto += HOWTO_BANK;
5292
5293 if (!rel->howto)
5294 {
5295 const char *name = S_GET_NAME (fixP->fx_addsy);
5296 if (name == NULL)
5297 name = "<unknown>";
1aea3bb8 5298 as_fatal ("Cannot generate relocation type for symbol %s, code %s",
9a736b6b 5299 name, bfd_get_reloc_code_name (code));
39bec121
TW
5300 return NULL;
5301 }
5302 return rel;
5303}
5304
d0313fb7 5305/* Handle cons expressions. */
9a736b6b 5306
39bec121
TW
5307void
5308tic54x_cons_fix_new (fragS *frag, int where, int octets, expressionS *exp)
5309{
5310 bfd_reloc_code_real_type r;
5311 switch (octets)
5312 {
5313 default:
5314 as_bad (_("Unsupported relocation size %d"), octets);
5315 r = BFD_RELOC_TIC54X_16_OF_23;
5316 break;
5317 case 2:
5318 r = BFD_RELOC_TIC54X_16_OF_23;
5319 break;
5320 case 4:
d0313fb7 5321 /* TI assembler always uses this, regardless of addressing mode. */
39bec121 5322 if (emitting_long)
9a736b6b 5323 r = BFD_RELOC_TIC54X_23;
39bec121 5324 else
9a736b6b
NC
5325 /* We never want to directly generate this; this is provided for
5326 stabs support only. */
5327 r = BFD_RELOC_32;
39bec121
TW
5328 break;
5329 }
5330 fix_new_exp (frag, where, octets, exp, 0, r);
5331}
5332
1aea3bb8 5333/* Attempt to simplify or even eliminate a fixup.
39bec121
TW
5334 To indicate that a fixup has been eliminated, set fixP->fx_done.
5335
d0313fb7 5336 If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry. */
9a736b6b 5337
39bec121
TW
5338int
5339md_apply_fix (fixP, valP)
5340 fixS *fixP;
5341 valueT *valP;
5342{
5343 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
5344 valueT val = *valP;
5345
5346 switch (fixP->fx_r_type)
5347 {
5348 default:
5349 as_fatal ("Bad relocation type: 0x%02x", fixP->fx_r_type);
5350 return 0;
5351 case BFD_RELOC_TIC54X_MS7_OF_23:
5352 val = (val >> 16) & 0x7F;
d0313fb7 5353 /* Fall through. */
39bec121
TW
5354 case BFD_RELOC_TIC54X_16_OF_23:
5355 case BFD_RELOC_16:
5356 bfd_put_16 (stdoutput, val, buf);
d0313fb7 5357 /* Indicate what we're actually writing, so that we don't get warnings
9a736b6b 5358 about exceeding available space. */
39bec121
TW
5359 *valP = val & 0xFFFF;
5360 break;
5361 case BFD_RELOC_TIC54X_PARTLS7:
5362 bfd_put_16 (stdoutput,
9a736b6b
NC
5363 (bfd_get_16 (stdoutput, buf) & 0xFF80) | (val & 0x7F),
5364 buf);
d0313fb7 5365 /* Indicate what we're actually writing, so that we don't get warnings
9a736b6b 5366 about exceeding available space. */
39bec121
TW
5367 *valP = val & 0x7F;
5368 break;
5369 case BFD_RELOC_TIC54X_PARTMS9:
5370 /* TI assembler doesn't shift its encoding for relocatable files, and is
9a736b6b 5371 thus incompatible with this implementation's relocatable files. */
1aea3bb8 5372 bfd_put_16 (stdoutput,
9a736b6b
NC
5373 (bfd_get_16 (stdoutput, buf) & 0xFE00) | (val >> 7),
5374 buf);
39bec121
TW
5375 break;
5376 case BFD_RELOC_32:
5377 case BFD_RELOC_TIC54X_23:
5378 bfd_put_32 (stdoutput,
9a736b6b
NC
5379 (bfd_get_32 (stdoutput, buf) & 0xFF800000) | val,
5380 buf);
39bec121
TW
5381 break;
5382 }
5383
d0313fb7 5384 return 0; /* Return value is ignored. */
39bec121
TW
5385}
5386
1aea3bb8 5387/* This is our chance to record section alignment
d0313fb7 5388 don't need to do anything here, since BFD does the proper encoding. */
9a736b6b 5389
39bec121
TW
5390valueT
5391md_section_align (segment, section_size)
5392 segT segment ATTRIBUTE_UNUSED;
5393 valueT section_size;
5394{
5395 return section_size;
5396}
5397
5398long
5399md_pcrel_from (fixP)
5400 fixS *fixP ATTRIBUTE_UNUSED;
5401{
5402 return 0;
5403}
5404
5405#if defined OBJ_COFF
5406
5407short
5408tc_coff_fix2rtype (fixP)
5409 fixS *fixP;
5410{
5411 return (fixP->fx_r_type);
5412}
5413
9a736b6b
NC
5414#endif /* OBJ_COFF */
5415
5416/* Mostly little-endian, but longwords (4 octets) get MS word stored
5417 first. */
39bec121 5418
39bec121
TW
5419void
5420tic54x_number_to_chars (buf, val, n)
9a736b6b
NC
5421 char *buf;
5422 valueT val;
5423 int n;
39bec121
TW
5424{
5425 if (n != 4)
9a736b6b 5426 number_to_chars_littleendian (buf, val, n);
39bec121
TW
5427 else
5428 {
1aea3bb8
NC
5429 number_to_chars_littleendian (buf , val >> 16 , 2);
5430 number_to_chars_littleendian (buf + 2, val & 0xFFFF, 2);
39bec121
TW
5431 }
5432}
5433
1aea3bb8 5434int
39bec121 5435tic54x_estimate_size_before_relax (frag, seg)
9a736b6b
NC
5436 fragS *frag ATTRIBUTE_UNUSED;
5437 segT seg ATTRIBUTE_UNUSED;
39bec121
TW
5438{
5439 return 0;
5440}
5441
d0313fb7
NC
5442/* We use this to handle bit allocations which we couldn't handle before due
5443 to symbols being in different frags. return number of octets added. */
9a736b6b 5444
1aea3bb8 5445int
39bec121 5446tic54x_relax_frag (frag, stretch)
1aea3bb8
NC
5447 fragS *frag;
5448 long stretch ATTRIBUTE_UNUSED;
39bec121
TW
5449{
5450 symbolS *sym = frag->fr_symbol;
5451 int growth = 0;
5452 int i;
5453
5454 if (sym != NULL)
5455 {
1aea3bb8 5456 struct bit_info *bi = (struct bit_info *) frag->fr_opcode;
39bec121
TW
5457 int bit_offset = frag_bit_offset (frag_prev (frag, bi->seg), bi->seg);
5458 int size = S_GET_VALUE (sym);
5459 fragS *prev_frag = bit_offset_frag (frag_prev (frag, bi->seg), bi->seg);
5460 int available = 16 - bit_offset;
5461
5462 if (symbol_get_frag (sym) != &zero_address_frag
9a736b6b
NC
5463 || S_IS_COMMON (sym)
5464 || !S_IS_DEFINED (sym))
5465 as_bad_where (frag->fr_file, frag->fr_line,
5466 _("non-absolute value used with .space/.bes"));
39bec121
TW
5467
5468 if (size < 0)
9a736b6b
NC
5469 {
5470 as_warn (_("negative value ignored in %s"),
5471 bi->type == TYPE_SPACE ? ".space" :
5472 bi->type == TYPE_BES ? ".bes" : ".field");
5473 growth = 0;
5474 frag->tc_frag_data = frag->fr_fix = 0;
5475 return 0;
5476 }
39bec121
TW
5477
5478 if (bi->type == TYPE_FIELD)
9a736b6b
NC
5479 {
5480 /* Bit fields of 16 or larger will have already been handled. */
5481 if (bit_offset != 0 && available >= size)
5482 {
5483 char *p = prev_frag->fr_literal;
5484 valueT value = bi->value;
5485 value <<= available - size;
5486 value |= ((unsigned short) p[1] << 8) | p[0];
5487 md_number_to_chars (p, value, 2);
5488 if ((prev_frag->tc_frag_data += size) == 16)
5489 prev_frag->tc_frag_data = 0;
5490 if (bi->sym)
5491 symbol_set_frag (bi->sym, prev_frag);
5492 /* This frag is no longer used. */
5493 growth = -frag->fr_fix;
5494 frag->fr_fix = 0;
5495 frag->tc_frag_data = 0;
5496 }
5497 else
5498 {
5499 char *p = frag->fr_literal;
5500 valueT value = bi->value << (16 - size);
5501 md_number_to_chars (p, value, 2);
5502 if ((frag->tc_frag_data = size) == 16)
5503 frag->tc_frag_data = 0;
5504 growth = 0;
5505 }
5506 }
39bec121 5507 else
9a736b6b
NC
5508 {
5509 if (bit_offset != 0 && bit_offset < 16)
5510 {
5511 if (available >= size)
5512 {
5513 if ((prev_frag->tc_frag_data += size) == 16)
5514 prev_frag->tc_frag_data = 0;
5515 if (bi->sym)
5516 symbol_set_frag (bi->sym, prev_frag);
5517 /* This frag is no longer used. */
5518 growth = -frag->fr_fix;
5519 frag->fr_fix = 0;
5520 frag->tc_frag_data = 0;
5521 goto getout;
5522 }
5523 if (bi->type == TYPE_SPACE && bi->sym)
5524 symbol_set_frag (bi->sym, prev_frag);
5525 size -= available;
5526 }
5527 growth = (size + 15) / 16 * OCTETS_PER_BYTE - frag->fr_fix;
5528 for (i = 0; i < growth; i++)
5529 frag->fr_literal[i] = 0;
5530 frag->fr_fix = growth;
5531 frag->tc_frag_data = size % 16;
5532 /* Make sure any BES label points to the LAST word allocated. */
5533 if (bi->type == TYPE_BES && bi->sym)
5534 S_SET_VALUE (bi->sym, frag->fr_fix / OCTETS_PER_BYTE - 1);
5535 }
39bec121
TW
5536 getout:
5537 frag->fr_symbol = 0;
5538 frag->fr_opcode = 0;
1aea3bb8 5539 free ((void *) bi);
39bec121
TW
5540 }
5541 return growth;
5542}
5543
5544void
5545tic54x_convert_frag (abfd, seg, frag)
1aea3bb8
NC
5546 bfd *abfd ATTRIBUTE_UNUSED;
5547 segT seg ATTRIBUTE_UNUSED;
5548 fragS *frag;
39bec121 5549{
d0313fb7 5550 /* Offset is in bytes. */
1aea3bb8 5551 frag->fr_offset = (frag->fr_next->fr_address
9a736b6b
NC
5552 - frag->fr_address
5553 - frag->fr_fix) / frag->fr_var;
39bec121
TW
5554 if (frag->fr_offset < 0)
5555 {
5556 as_bad_where (frag->fr_file, frag->fr_line,
9a736b6b
NC
5557 _("attempt to .space/.bes backwards? (%ld)"),
5558 (long) frag->fr_offset);
39bec121
TW
5559 }
5560 frag->fr_type = rs_space;
5561}
5562
d0313fb7 5563/* We need to avoid having labels defined for certain directives/pseudo-ops
39bec121
TW
5564 since once the label is defined, it's in the symbol table for good. TI
5565 syntax puts the symbol *before* the pseudo (which is kinda like MRI syntax,
5566 I guess, except I've never seen a definition of MRI syntax).
5567
5568 C is the character that used to be at *REST, which points to the end of the
1aea3bb8 5569 label.
39bec121 5570
d0313fb7 5571 Don't allow labels to start with '.' */
9a736b6b 5572
39bec121
TW
5573int
5574tic54x_start_label (c, rest)
1aea3bb8
NC
5575 int c;
5576 char *rest;
39bec121 5577{
d0313fb7 5578 /* If within .struct/.union, no auto line labels, please. */
39bec121
TW
5579 if (current_stag != NULL)
5580 return 0;
5581
d0313fb7 5582 /* Disallow labels starting with "." */
39bec121
TW
5583 if (c != ':')
5584 {
5585 char *label = rest;
1aea3bb8 5586 while (!is_end_of_line[(int) label[-1]])
9a736b6b 5587 --label;
39bec121 5588 if (*label == '.')
9a736b6b
NC
5589 {
5590 as_bad (_("Invalid label '%s'"), label);
5591 return 0;
5592 }
39bec121
TW
5593 }
5594
1aea3bb8 5595 if (is_end_of_line[(int) c])
39bec121
TW
5596 return 1;
5597
3882b010
L
5598 if (ISSPACE (c))
5599 while (ISSPACE (c = *++rest))
39bec121
TW
5600 ;
5601 if (c == '.')
5602 {
d0313fb7 5603 /* Don't let colon () define a label for any of these... */
3882b010
L
5604 return (strncasecmp (rest, ".tag", 4) != 0 || !ISSPACE (rest[4]))
5605 && (strncasecmp (rest, ".struct", 7) != 0 || !ISSPACE (rest[7]))
5606 && (strncasecmp (rest, ".union", 6) != 0 || !ISSPACE (rest[6]))
5607 && (strncasecmp (rest, ".macro", 6) != 0 || !ISSPACE (rest[6]))
5608 && (strncasecmp (rest, ".set", 4) != 0 || !ISSPACE (rest[4]))
5609 && (strncasecmp (rest, ".equ", 4) != 0 || !ISSPACE (rest[4]));
39bec121
TW
5610 }
5611
5612 return 1;
5613}
This page took 0.360312 seconds and 4 git commands to generate.