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