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