Back to index

cell-binutils  2.17cvs20070401
tc-tic54x.c
Go to the documentation of this file.
00001 /* tc-tic54x.c -- Assembly code for the Texas Instruments TMS320C54X
00002    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
00003    Free Software Foundation, Inc.
00004    Contributed by Timothy Wall (twall@cygnus.com)
00005 
00006    This file is part of GAS, the GNU Assembler.
00007 
00008    GAS is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2, or (at your option)
00011    any later version.
00012 
00013    GAS is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with GAS; see the file COPYING.  If not, write to the Free
00020    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00021    02110-1301, USA.  */
00022 
00023 /* Texas Instruments TMS320C54X machine specific gas.
00024    Written by Timothy Wall (twall@alum.mit.edu).
00025 
00026    Valuable things to do:
00027    Pipeline conflict warnings
00028    We encode/decode "ld #_label, dp" differently in relocatable files
00029      This means we're not compatible with TI output containing those
00030      expressions.  We store the upper nine bits; TI stores the lower nine
00031      bits.  How they recover the original upper nine bits is beyond me.
00032 
00033    Tests to add to expect testsuite:
00034      '=' and '==' with .if, .elseif, and .break
00035 
00036    Incompatibilities (mostly trivial):
00037    We don't allow '''
00038    We fill text section with zeroes instead of "nop"s
00039    We don't convert '' or "" to a single instance
00040    We don't convert '' to '\0'
00041    We don't allow strings with .byte/.half/.short/.long
00042    Probably details of the subsym stuff are different
00043    TI sets labels to be data type 4 (T_INT); GAS uses T_NULL.
00044 
00045    COFF1 limits section names to 8 characters.
00046    Some of the default behavior changed from COFF1 to COFF2.  */
00047 
00048 #include <limits.h>
00049 #include "as.h"
00050 #include "safe-ctype.h"
00051 #include "sb.h"
00052 #include "macro.h"
00053 #include "subsegs.h"
00054 #include "struc-symbol.h"
00055 #include "opcode/tic54x.h"
00056 #include "obj-coff.h"
00057 #include <math.h>
00058 
00059 
00060 static struct stag
00061 {
00062   symbolS *sym;                     /* Symbol for this stag; value is offset.  */
00063   const char *name;         /* Shortcut to symbol name.  */
00064   bfd_vma size;                     /* Size of struct/union.  */
00065   int current_bitfield_offset;  /* Temporary for tracking fields.  */
00066   int is_union;
00067   struct stag_field         /* List of fields.  */
00068   {
00069     const char *name;
00070     bfd_vma offset;         /* Of start of this field.  */
00071     int bitfield_offset;    /* Of start of this field.  */
00072     struct stag *stag;              /* If field is struct/union.  */
00073     struct stag_field *next;
00074   } *field;
00075   /* For nesting; used only in stag construction.  */
00076   struct stag *inner;               /* Enclosed .struct.  */
00077   struct stag *outer;               /* Enclosing .struct.  */
00078 } *current_stag = NULL;
00079 
00080 #define MAX_LINE 256 /* Lines longer than this are truncated by TI's asm.  */
00081 
00082 typedef struct _tic54x_insn
00083 {
00084   const template *tm;              /* Opcode template.  */
00085 
00086   char mnemonic[MAX_LINE];  /* Opcode name/mnemonic.  */
00087   char parmnemonic[MAX_LINE];   /* 2nd mnemonic of parallel insn.  */
00088 
00089   int opcount;
00090   struct opstruct
00091   {
00092     char buf[MAX_LINE];
00093     enum optype type;
00094     expressionS exp;
00095   } operands[MAX_OPERANDS];
00096 
00097   int paropcount;
00098   struct opstruct paroperands[MAX_OPERANDS];
00099 
00100   int is_lkaddr;
00101   int lkoperand;
00102   int words;                /* Size of insn in 16-bit words.  */
00103   int using_default_dst;    /* Do we need to explicitly set an
00104                                omitted OP_DST operand?  */
00105   struct
00106   {
00107     unsigned short word;         /* Final encoded opcode data.  */
00108     int unresolved;
00109     int r_nchars;                /* Relocation size.  */
00110     bfd_reloc_code_real_type r_type; /* Relocation type.  */
00111     expressionS addr_expr;       /* Storage for unresolved expressions.  */
00112   } opcode[3];
00113 } tic54x_insn;
00114 
00115 enum cpu_version
00116 {
00117   VNONE = 0, V541 = 1, V542 = 2, V543 = 3, V545 = 5, V548 = 8, V549 = 9,
00118   V545LP = 15, V546LP = 16
00119 };
00120 
00121 enum address_mode
00122 {
00123   c_mode,   /* 16-bit addresses.  */
00124   far_mode  /* >16-bit addresses.  */
00125 };
00126 
00127 static segT stag_saved_seg;
00128 static subsegT stag_saved_subseg;
00129 
00130 const char comment_chars[] = ";";
00131 const char line_comment_chars[] = ";*#"; /* At column zero only.  */
00132 const char line_separator_chars[] = ""; /* Not permitted.  */
00133 
00134 int emitting_long = 0;
00135 
00136 /* Characters which indicate that this is a floating point constant.  */
00137 const char FLT_CHARS[] = "fF";
00138 
00139 /* Characters that can be used to separate mantissa from exp in FP
00140    nums.  */
00141 const char EXP_CHARS[] = "eE";
00142 
00143 const char *md_shortopts = "";
00144 
00145 #define OPTION_ADDRESS_MODE     (OPTION_MD_BASE)
00146 #define OPTION_CPU_VERSION      (OPTION_ADDRESS_MODE + 1)
00147 #define OPTION_COFF_VERSION     (OPTION_CPU_VERSION + 1)
00148 #define OPTION_STDERR_TO_FILE   (OPTION_COFF_VERSION + 1)
00149 
00150 struct option md_longopts[] =
00151 {
00152   { "mfar-mode",       no_argument,           NULL, OPTION_ADDRESS_MODE },
00153   { "mf",            no_argument,      NULL, OPTION_ADDRESS_MODE },
00154   { "mcpu",          required_argument,   NULL, OPTION_CPU_VERSION },
00155   { "merrors-to-file", required_argument,   NULL, OPTION_STDERR_TO_FILE },
00156   { "me",            required_argument,   NULL, OPTION_STDERR_TO_FILE },
00157   { NULL,              no_argument,         NULL, 0},
00158 };
00159 
00160 size_t md_longopts_size = sizeof (md_longopts);
00161 
00162 static int assembly_begun = 0;
00163 /* Addressing mode is not entirely implemented; the latest rev of the Other
00164    assembler doesn't seem to make any distinction whatsoever; all relocations
00165    are stored as extended relocatiosn.  Older versions used REL16 vs RELEXT16,
00166    but now it seems all relocations are RELEXT16.  We use all RELEXT16.
00167 
00168    The cpu version is kind of a waste of time as well.  There is one
00169    instruction (RND) for LP devices only, and several for devices with
00170    extended addressing only.  We include it for compatibility.  */
00171 static enum address_mode amode = c_mode;
00172 static enum cpu_version cpu = VNONE;
00173 
00174 /* Include string substitutions in listing?  */
00175 static int listing_sslist = 0;
00176 
00177 /* Did we do subsym substitutions on the line?  */
00178 static int substitution_line = 0;
00179 
00180 /* Last label seen.  */
00181 static symbolS *last_label_seen = NULL;
00182 
00183 /* This ensures that all new labels are unique.  */
00184 static int local_label_id;
00185 
00186 static struct hash_control *subsym_recurse_hash; /* Prevent infinite recurse.  */
00187 static struct hash_control *math_hash; /* Built-in math functions.  */
00188 /* Allow maximum levels of macro nesting; level 0 is the main substitution
00189    symbol table.  The other assembler only does 32 levels, so there!  */
00190 static struct hash_control *subsym_hash[100];
00191 
00192 /* Keep track of local labels so we can substitute them before GAS sees them
00193    since macros use their own 'namespace' for local labels, use a separate hash
00194 
00195    We do our own local label handling 'cuz it's subtly different from the
00196    stock GAS handling.
00197 
00198    We use our own macro nesting counter, since GAS overloads it when expanding
00199    other things (like conditionals and repeat loops).  */
00200 static int macro_level = 0;
00201 static struct hash_control *local_label_hash[100];
00202 /* Keep track of struct/union tags.  */
00203 static struct hash_control *stag_hash;
00204 static struct hash_control *op_hash;
00205 static struct hash_control *parop_hash;
00206 static struct hash_control *reg_hash;
00207 static struct hash_control *mmreg_hash;
00208 static struct hash_control *cc_hash;
00209 static struct hash_control *cc2_hash;
00210 static struct hash_control *cc3_hash;
00211 static struct hash_control *sbit_hash;
00212 static struct hash_control *misc_symbol_hash;
00213 
00214 /* Only word (et al.), align, or conditionals are allowed within
00215    .struct/.union.  */
00216 #define ILLEGAL_WITHIN_STRUCT()                                \
00217   do                                                    \
00218     if (current_stag != NULL)                                  \
00219       {                                                 \
00220        as_bad (_("pseudo-op illegal within .struct/.union"));  \
00221        return;                                                 \
00222       }                                                        \
00223   while (0)
00224 
00225 static void   tic54x_emit_char     PARAMS ((char));
00226 static fragS *       frag_prev            PARAMS ((fragS *, segT));
00227 static fragS *       bit_offset_frag      PARAMS ((fragS *, segT));
00228 static int    frag_bit_offset      PARAMS ((fragS *, segT));
00229 static char * parse_expression     PARAMS ((char *, expressionS *));
00230 static void   tic54x_asg           PARAMS ((int));
00231 static void   tic54x_eval          PARAMS ((int));
00232 static void   tic54x_bss           PARAMS ((int));
00233 static void   stag_add_field_symbols      PARAMS ((struct stag *, const char *, bfd_vma, symbolS *, const char *));
00234 static void   stag_add_field              PARAMS ((struct stag *, const char *, bfd_vma, struct stag *));
00235 static void   tic54x_struct               PARAMS ((int));
00236 static void   tic54x_endstruct     PARAMS ((int));
00237 static void   tic54x_tag           PARAMS ((int));
00238 static void   tic54x_struct_field  PARAMS ((int));
00239 static void   tic54x_cons          PARAMS ((int));
00240 static void   tic54x_remove_local_label PARAMS ((const char *, PTR));
00241 static void   tic54x_clear_local_labels PARAMS ((int));
00242 static void   tic54x_sect          PARAMS ((int));
00243 static void   tic54x_space         PARAMS ((int));
00244 static void   tic54x_usect         PARAMS ((int));
00245 static enum cpu_version lookup_version    PARAMS ((const char *));
00246 static void   set_cpu              PARAMS ((enum cpu_version));
00247 static void   tic54x_version              PARAMS ((int));
00248 static void   tic54x_float_cons    PARAMS ((int));
00249 static void   tic54x_stringer      PARAMS ((int));
00250 static void   tic54x_p2align              PARAMS ((int));
00251 static void   tic54x_align_words   PARAMS ((int));
00252 static void   tic54x_field         PARAMS ((int));
00253 static int    tic54x_initialized_section PARAMS ((segT));
00254 static void   tic54x_clink         PARAMS ((int));
00255 static void   tic54x_set_default_include PARAMS ((int));
00256 static void   tic54x_include              PARAMS ((int));
00257 static void   tic54x_message              PARAMS ((int));
00258 static void   tic54x_label         PARAMS ((int));
00259 static void   tic54x_mmregs               PARAMS ((int));
00260 static void   tic54x_loop          PARAMS ((int));
00261 static void   tic54x_endloop              PARAMS ((int));
00262 static void   tic54x_break         PARAMS ((int));
00263 static void   set_address_mode     PARAMS ((int));
00264 static void   tic54x_address_mode  PARAMS ((int));
00265 static void   tic54x_sblock               PARAMS ((int));
00266 static void   tic54x_set           PARAMS ((int));
00267 static void   tic54x_fclist               PARAMS ((int));
00268 static void   tic54x_sslist               PARAMS ((int));
00269 static void   tic54x_var           PARAMS ((int));
00270 static void   tic54x_mlib          PARAMS ((int));
00271 static int    subsym_symlen               PARAMS ((char *, char *));
00272 static int    subsym_symcmp               PARAMS ((char *, char *));
00273 static int    subsym_firstch              PARAMS ((char *, char *));
00274 static int    subsym_lastch               PARAMS ((char *, char *));
00275 static int    subsym_isdefed              PARAMS ((char *, char *));
00276 static int    subsym_ismember      PARAMS ((char *, char *));
00277 static int    subsym_iscons               PARAMS ((char *, char *));
00278 static int    subsym_isname               PARAMS ((char *, char *));
00279 static int    subsym_isreg         PARAMS ((char *, char *));
00280 static int    subsym_structsz      PARAMS ((char *, char *));
00281 static int    subsym_structacc     PARAMS ((char *, char *));
00282 static float  math_ceil            PARAMS ((float, float));
00283 static float  math_cvi             PARAMS ((float, float));
00284 static float  math_floor           PARAMS ((float, float));
00285 static float  math_fmod            PARAMS ((float, float));
00286 static float  math_int             PARAMS ((float, float));
00287 static float  math_round           PARAMS ((float, float));
00288 static float  math_sgn             PARAMS ((float, float));
00289 static float  math_trunc           PARAMS ((float, float));
00290 static float  math_acos            PARAMS ((float, float));
00291 static float  math_asin            PARAMS ((float, float));
00292 static float  math_atan            PARAMS ((float, float));
00293 static float  math_atan2           PARAMS ((float, float));
00294 static float  math_cosh            PARAMS ((float, float));
00295 static float  math_cos             PARAMS ((float, float));
00296 static float  math_cvf             PARAMS ((float, float));
00297 static float  math_exp             PARAMS ((float, float));
00298 static float  math_fabs            PARAMS ((float, float));
00299 static float  math_ldexp           PARAMS ((float, float));
00300 static float  math_log10           PARAMS ((float, float));
00301 static float  math_log             PARAMS ((float, float));
00302 static float  math_max             PARAMS ((float, float));
00303 static float  math_min             PARAMS ((float, float));
00304 static float  math_pow             PARAMS ((float, float));
00305 static float  math_sin             PARAMS ((float, float));
00306 static float  math_sinh            PARAMS ((float, float));
00307 static float  math_sqrt            PARAMS ((float, float));
00308 static float  math_tan             PARAMS ((float, float));
00309 static float  math_tanh            PARAMS ((float, float));
00310 static int    is_accumulator              PARAMS ((struct opstruct *));
00311 static int    get_operands         PARAMS ((struct opstruct operands[], char *));
00312 static int    is_immediate         PARAMS ((struct opstruct *));
00313 static int    is_absolute          PARAMS ((struct opstruct *));
00314 static int    is_indirect          PARAMS ((struct opstruct *));
00315 static int    is_dual              PARAMS ((struct opstruct *));
00316 static int    is_mmreg             PARAMS ((struct opstruct *));
00317 static int    is_type              PARAMS ((struct opstruct *, enum optype));
00318 static int    operands_match              PARAMS ((tic54x_insn *, struct opstruct *, int, const enum optype *, int, int));
00319 static int    encode_dmad          PARAMS ((tic54x_insn *, struct opstruct *, int));
00320 static int    encode_address              PARAMS ((tic54x_insn *, struct opstruct *));
00321 static int    encode_indirect      PARAMS ((tic54x_insn *, struct opstruct *));
00322 static int    encode_integer              PARAMS ((tic54x_insn *, struct opstruct *, int, int, int, unsigned short));
00323 static int    encode_condition     PARAMS ((tic54x_insn *, struct opstruct *));
00324 static int    encode_cc3           PARAMS ((tic54x_insn *, struct opstruct *));
00325 static int    encode_arx           PARAMS ((tic54x_insn *, struct opstruct *));
00326 static int    encode_cc2           PARAMS ((tic54x_insn *, struct opstruct *));
00327 static int    encode_operand              PARAMS ((tic54x_insn *, enum optype, struct opstruct *));
00328 static void   emit_insn            PARAMS ((tic54x_insn *));
00329 static int    build_insn           PARAMS ((tic54x_insn *));
00330 static int    optimize_insn               PARAMS ((tic54x_insn *));
00331 static int    tic54x_parse_insn    PARAMS ((tic54x_insn *, char *));
00332 static int    next_line_shows_parallel PARAMS ((char *));
00333 static int    tic54x_parse_parallel_insn_firstline PARAMS ((tic54x_insn *, char *));
00334 static int    tic54x_parse_parallel_insn_lastline PARAMS ((tic54x_insn *, char *));
00335 static char * subsym_get_arg              PARAMS ((char *, char *, char **, int));
00336 static void   subsym_create_or_replace PARAMS ((char *, char *));
00337 static char * subsym_lookup               PARAMS ((char *, int));
00338 static char * subsym_substitute    PARAMS ((char *, int));
00339 
00340 
00341 void
00342 md_show_usage (stream)
00343      FILE *stream;
00344 {
00345   fprintf (stream, _("C54x-specific command line  options:\n"));
00346   fprintf (stream, _("-mfar-mode | -mf          Use extended addressing\n"));
00347   fprintf (stream, _("-mcpu=<CPU version>       Specify the CPU version\n"));
00348   fprintf (stream, _("-merrors-to-file <filename>\n"));
00349   fprintf (stream, _("-me <filename>            Redirect errors to a file\n"));
00350 }
00351 
00352 /* Output a single character (upper octect is zero).  */
00353 
00354 static void
00355 tic54x_emit_char (c)
00356      char c;
00357 {
00358   expressionS exp;
00359 
00360   exp.X_op = O_constant;
00361   exp.X_add_number = c;
00362   emit_expr (&exp, 2);
00363 }
00364 
00365 /* Walk backwards in the frag chain.  */
00366 
00367 static fragS *
00368 frag_prev (frag, seg)
00369      fragS *frag;
00370      segT seg;
00371 {
00372   segment_info_type *seginfo = seg_info (seg);
00373   fragS *fragp;
00374 
00375   for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
00376     if (fragp->fr_next == frag)
00377       return fragp;
00378 
00379   return NULL;
00380 }
00381 
00382 static fragS *
00383 bit_offset_frag (frag, seg)
00384      fragS *frag;
00385      segT seg;
00386 {
00387   while (frag != NULL)
00388     {
00389       if (frag->fr_fix == 0
00390          && frag->fr_opcode == NULL
00391          && frag->tc_frag_data == 0)
00392        frag = frag_prev (frag, seg);
00393       else
00394        return frag;
00395     }
00396   return NULL;
00397 }
00398 
00399 /* Return the number of bits allocated in the most recent word, or zero if
00400    none. .field/.space/.bes may leave words partially allocated.  */
00401 
00402 static int
00403 frag_bit_offset (frag, seg)
00404      fragS *frag;
00405      segT seg;
00406 {
00407   frag = bit_offset_frag (frag, seg);
00408 
00409   if (frag)
00410     return frag->fr_opcode != NULL ? -1 : frag->tc_frag_data;
00411 
00412   return 0;
00413 }
00414 
00415 /* Read an expression from a C string; returns a pointer past the end of the
00416    expression.  */
00417 
00418 static char *
00419 parse_expression (str, exp)
00420      char *str;
00421      expressionS * exp;
00422 {
00423   char *s;
00424   char *tmp;
00425 
00426   tmp = input_line_pointer; /* Save line pointer.  */
00427   input_line_pointer = str;
00428   expression (exp);
00429   s = input_line_pointer;
00430   input_line_pointer = tmp; /* Restore line pointer.  */
00431   return s;                 /* Return pointer to where parsing stopped.  */
00432 }
00433 
00434 /* .asg "character-string"|character-string, symbol
00435 
00436    .eval is the only pseudo-op allowed to perform arithmetic on substitution
00437    symbols.  all other use of symbols defined with .asg are currently
00438    unsupported.  */
00439 
00440 static void
00441 tic54x_asg (x)
00442      int x ATTRIBUTE_UNUSED;
00443 {
00444   int c;
00445   char *name;
00446   char *str;
00447   char *tmp;
00448   int quoted = *input_line_pointer == '"';
00449 
00450   ILLEGAL_WITHIN_STRUCT ();
00451 
00452   if (quoted)
00453     {
00454       int len;
00455       str = demand_copy_C_string (&len);
00456       c = *input_line_pointer;
00457     }
00458   else
00459     {
00460       str = input_line_pointer;
00461       while ((c = *input_line_pointer) != ',')
00462        {
00463          if (is_end_of_line[(int) *input_line_pointer])
00464            break;
00465          ++input_line_pointer;
00466        }
00467       *input_line_pointer = 0;
00468     }
00469   if (c != ',')
00470     {
00471       as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'"));
00472       ignore_rest_of_line ();
00473       return;
00474     }
00475 
00476   name = ++input_line_pointer;
00477   c = get_symbol_end ();    /* Get terminator.  */
00478   if (!ISALPHA (*name))
00479     {
00480       as_bad ("symbols assigned with .asg must begin with a letter");
00481       ignore_rest_of_line ();
00482       return;
00483     }
00484 
00485   tmp = xmalloc (strlen (str) + 1);
00486   strcpy (tmp, str);
00487   str = tmp;
00488   tmp = xmalloc (strlen (name) + 1);
00489   strcpy (tmp, name);
00490   name = tmp;
00491   subsym_create_or_replace (name, str);
00492   *input_line_pointer = c;
00493   demand_empty_rest_of_line ();
00494 }
00495 
00496 /* .eval expression, symbol
00497    There's something screwy about this.  The other assembler sometimes does and
00498    sometimes doesn't substitute symbols defined with .eval.
00499    We'll put the symbols into the subsym table as well as the normal symbol
00500    table, since that's what works best.  */
00501 
00502 static void
00503 tic54x_eval (x)
00504      int x ATTRIBUTE_UNUSED;
00505 {
00506   char c;
00507   int value;
00508   char *name;
00509   symbolS *symbolP;
00510   char valuestr[32], *tmp;
00511   int quoted;
00512 
00513   ILLEGAL_WITHIN_STRUCT ();
00514 
00515   SKIP_WHITESPACE ();
00516 
00517   quoted = *input_line_pointer == '"';
00518   if (quoted)
00519     ++input_line_pointer;
00520   value = get_absolute_expression ();
00521   if (quoted)
00522     {
00523       if (*input_line_pointer != '"')
00524        {
00525          as_bad (_("Unterminated string after absolute expression"));
00526          ignore_rest_of_line ();
00527          return;
00528        }
00529       ++input_line_pointer;
00530     }
00531   if (*input_line_pointer++ != ',')
00532     {
00533       as_bad (_("Comma and symbol expected for '.eval EXPR, SYMBOL'"));
00534       ignore_rest_of_line ();
00535       return;
00536     }
00537   name = input_line_pointer;
00538   c = get_symbol_end ();    /* Get terminator.  */
00539   tmp = xmalloc (strlen (name) + 1);
00540   name = strcpy (tmp, name);
00541   *input_line_pointer = c;
00542 
00543   if (!ISALPHA (*name))
00544     {
00545       as_bad (_("symbols assigned with .eval must begin with a letter"));
00546       ignore_rest_of_line ();
00547       return;
00548     }
00549   symbolP = symbol_new (name, absolute_section,
00550                      (valueT) value, &zero_address_frag);
00551   SF_SET_LOCAL (symbolP);
00552   symbol_table_insert (symbolP);
00553 
00554   /* The "other" assembler sometimes doesn't put .eval's in the subsym table
00555      But since there's not written rule as to when, don't even bother trying
00556      to match their behavior.  */
00557   sprintf (valuestr, "%d", value);
00558   tmp = xmalloc (strlen (valuestr) + 1);
00559   strcpy (tmp, valuestr);
00560   subsym_create_or_replace (name, tmp);
00561 
00562   demand_empty_rest_of_line ();
00563 }
00564 
00565 /* .bss symbol, size [, [blocking flag] [, alignment flag]
00566 
00567    alignment is to a longword boundary; blocking is to 128-word boundary.
00568 
00569    1) if there is a hole in memory, this directive should attempt to fill it
00570       (not yet implemented).
00571 
00572    2) if the blocking flag is not set, allocate at the current SPC
00573       otherwise, check to see if the current SPC plus the space to be
00574       allocated crosses the page boundary (128 words).
00575       if there's not enough space, create a hole and align with the next page
00576       boundary.
00577       (not yet implemented).  */
00578 
00579 static void
00580 tic54x_bss (x)
00581      int x ATTRIBUTE_UNUSED;
00582 {
00583   char c;
00584   char *name;
00585   char *p;
00586   int words;
00587   segT current_seg;
00588   subsegT current_subseg;
00589   symbolS *symbolP;
00590   int block = 0;
00591   int align = 0;
00592 
00593   ILLEGAL_WITHIN_STRUCT ();
00594 
00595   current_seg = now_seg;    /* Save current seg.  */
00596   current_subseg = now_subseg;     /* Save current subseg.  */
00597 
00598   name = input_line_pointer;
00599   c = get_symbol_end ();    /* Get terminator.  */
00600   if (c != ',')
00601     {
00602       as_bad (".bss size argument missing\n");
00603       ignore_rest_of_line ();
00604       return;
00605     }
00606 
00607   ++input_line_pointer;
00608   words = get_absolute_expression ();
00609   if (words < 0)
00610     {
00611       as_bad (".bss size %d < 0!", words);
00612       ignore_rest_of_line ();
00613       return;
00614     }
00615 
00616   if (*input_line_pointer == ',')
00617     {
00618       /* The blocking flag may be missing.  */
00619       ++input_line_pointer;
00620       if (*input_line_pointer != ',')
00621        block = get_absolute_expression ();
00622       else
00623        block = 0;
00624 
00625       if (*input_line_pointer == ',')
00626        {
00627          ++input_line_pointer;
00628          align = get_absolute_expression ();
00629        }
00630       else
00631        align = 0;
00632     }
00633   else
00634     block = align = 0;
00635 
00636   subseg_set (bss_section, 0);
00637   symbolP = symbol_find_or_make (name);
00638 
00639   if (S_GET_SEGMENT (symbolP) == bss_section)
00640     symbolP->sy_frag->fr_symbol = (symbolS *) NULL;
00641 
00642   symbol_set_frag (symbolP, frag_now);
00643   p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
00644               (offsetT) (words * OCTETS_PER_BYTE), (char *) 0);
00645   *p = 0;                   /* Fill char.  */
00646 
00647   S_SET_SEGMENT (symbolP, bss_section);
00648 
00649   /* The symbol may already have been created with a preceding
00650      ".globl" directive -- be careful not to step on storage class
00651      in that case.  Otherwise, set it to static.  */
00652   if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
00653     S_SET_STORAGE_CLASS (symbolP, C_STAT);
00654 
00655   if (align)
00656     {
00657       /* s_align eats end of line; restore it */
00658       s_align_bytes (4);
00659       --input_line_pointer;
00660     }
00661 
00662   if (block)
00663     bss_section->flags |= SEC_TIC54X_BLOCK;
00664 
00665   subseg_set (current_seg, current_subseg);      /* Restore current seg.  */
00666   demand_empty_rest_of_line ();
00667 }
00668 
00669 static void
00670 stag_add_field_symbols (stag, path, base_offset, rootsym, root_stag_name)
00671      struct stag *stag;
00672      const char *path;
00673      bfd_vma base_offset;
00674      symbolS *rootsym;
00675      const char *root_stag_name;
00676 {
00677   char prefix[strlen (path) + 2];
00678   struct stag_field *field = stag->field;
00679 
00680   /* Construct a symbol for every field contained within this structure
00681      including fields within structure fields.  */
00682   strcpy (prefix, path);
00683   if (*path)
00684     strcat (prefix, ".");
00685 
00686   while (field != NULL)
00687     {
00688       int len = strlen (prefix) + strlen (field->name) + 2;
00689       char *name = xmalloc (len);
00690       strcpy (name, prefix);
00691       strcat (name, field->name);
00692 
00693       if (rootsym == NULL)
00694        {
00695          symbolS *sym;
00696          sym = symbol_new (name, absolute_section,
00697                          (field->stag ? field->offset :
00698                           (valueT) (base_offset + field->offset)),
00699                          &zero_address_frag);
00700          SF_SET_LOCAL (sym);
00701          symbol_table_insert (sym);
00702        }
00703       else
00704        {
00705          char *replacement = xmalloc (strlen (name)
00706                                    + strlen (stag->name) + 2);
00707          strcpy (replacement, S_GET_NAME (rootsym));
00708          strcat (replacement, "+");
00709          strcat (replacement, root_stag_name);
00710          strcat (replacement, name + strlen (S_GET_NAME (rootsym)));
00711          hash_insert (subsym_hash[0], name, replacement);
00712        }
00713 
00714       /* Recurse if the field is a structure.
00715         Note the field offset is relative to the outermost struct.  */
00716       if (field->stag != NULL)
00717        stag_add_field_symbols (field->stag, name,
00718                             field->offset,
00719                             rootsym, root_stag_name);
00720       field = field->next;
00721     }
00722 }
00723 
00724 /* Keep track of stag fields so that when structures are nested we can add the
00725    complete dereferencing symbols to the symbol table.  */
00726 
00727 static void
00728 stag_add_field (parent, name, offset, stag)
00729      struct stag *parent;
00730      const char *name;
00731      bfd_vma offset;
00732      struct stag *stag;
00733 {
00734   struct stag_field *sfield = xmalloc (sizeof (struct stag_field));
00735 
00736   memset (sfield, 0, sizeof (*sfield));
00737   sfield->name = strcpy (xmalloc (strlen (name) + 1), name);
00738   sfield->offset = offset;
00739   sfield->bitfield_offset = parent->current_bitfield_offset;
00740   sfield->stag = stag;
00741   if (parent->field == NULL)
00742     parent->field = sfield;
00743   else
00744     {
00745       struct stag_field *sf = parent->field;
00746       while (sf->next != NULL)
00747        sf = sf->next;
00748       sf->next = sfield;
00749     }
00750   /* Only create a symbol for this field if the parent has no name.  */
00751   if (!strncmp (".fake", parent->name, 5))
00752     {
00753       symbolS *sym = symbol_new (name, absolute_section,
00754                              (valueT) offset, &zero_address_frag);
00755       SF_SET_LOCAL (sym);
00756       symbol_table_insert (sym);
00757     }
00758 }
00759 
00760 /* [STAG] .struct       [OFFSET]
00761    Start defining structure offsets (symbols in absolute section).  */
00762 
00763 static void
00764 tic54x_struct (arg)
00765      int arg;
00766 {
00767   int start_offset = 0;
00768   int is_union = arg;
00769 
00770   if (!current_stag)
00771     {
00772       /* Starting a new struct, switch to absolute section.  */
00773       stag_saved_seg = now_seg;
00774       stag_saved_subseg = now_subseg;
00775       subseg_set (absolute_section, 0);
00776     }
00777   /* Align the current pointer.  */
00778   else if (current_stag->current_bitfield_offset != 0)
00779     {
00780       ++abs_section_offset;
00781       current_stag->current_bitfield_offset = 0;
00782     }
00783 
00784   /* Offset expression is only meaningful for global .structs.  */
00785   if (!is_union)
00786     {
00787       /* Offset is ignored in inner structs.  */
00788       SKIP_WHITESPACE ();
00789       if (!is_end_of_line[(int) *input_line_pointer])
00790        start_offset = get_absolute_expression ();
00791       else
00792        start_offset = 0;
00793     }
00794 
00795   if (current_stag)
00796     {
00797       /* Nesting, link to outer one.  */
00798       current_stag->inner = (struct stag *) xmalloc (sizeof (struct stag));
00799       memset (current_stag->inner, 0, sizeof (struct stag));
00800       current_stag->inner->outer = current_stag;
00801       current_stag = current_stag->inner;
00802       if (start_offset)
00803        as_warn (_("Offset on nested structures is ignored"));
00804       start_offset = abs_section_offset;
00805     }
00806   else
00807     {
00808       current_stag = (struct stag *) xmalloc (sizeof (struct stag));
00809       memset (current_stag, 0, sizeof (struct stag));
00810       abs_section_offset = start_offset;
00811     }
00812   current_stag->is_union = is_union;
00813 
00814   if (line_label == NULL)
00815     {
00816       static int struct_count = 0;
00817       char fake[] = ".fake_stagNNNNNNN";
00818       sprintf (fake, ".fake_stag%d", struct_count++);
00819       current_stag->sym = symbol_new (fake, absolute_section,
00820                                   (valueT) abs_section_offset,
00821                                   &zero_address_frag);
00822     }
00823   else
00824     {
00825       char label[strlen (S_GET_NAME (line_label)) + 1];
00826       strcpy (label, S_GET_NAME (line_label));
00827       current_stag->sym = symbol_new (label, absolute_section,
00828                                   (valueT) abs_section_offset,
00829                                   &zero_address_frag);
00830     }
00831   current_stag->name = S_GET_NAME (current_stag->sym);
00832   SF_SET_LOCAL (current_stag->sym);
00833   /* Nested .structs don't go into the symbol table.  */
00834   if (current_stag->outer == NULL)
00835     symbol_table_insert (current_stag->sym);
00836 
00837   line_label = NULL;
00838 }
00839 
00840 /* [LABEL] .endstruct
00841    finish defining structure offsets; optional LABEL's value will be the size
00842    of the structure.  */
00843 
00844 static void
00845 tic54x_endstruct (is_union)
00846      int is_union;
00847 {
00848   int size;
00849   const char *path =
00850     !strncmp (current_stag->name, ".fake", 5) ? "" : current_stag->name;
00851 
00852   if (!current_stag || current_stag->is_union != is_union)
00853     {
00854       as_bad (_(".end%s without preceding .%s"),
00855              is_union ? "union" : "struct",
00856              is_union ? "union" : "struct");
00857       ignore_rest_of_line ();
00858       return;
00859     }
00860 
00861   /* Align end of structures.  */
00862   if (current_stag->current_bitfield_offset)
00863     {
00864       ++abs_section_offset;
00865       current_stag->current_bitfield_offset = 0;
00866     }
00867 
00868   if (current_stag->is_union)
00869     size = current_stag->size;
00870   else
00871     size = abs_section_offset - S_GET_VALUE (current_stag->sym);
00872   if (line_label != NULL)
00873     {
00874       S_SET_VALUE (line_label, size);
00875       symbol_table_insert (line_label);
00876       line_label = NULL;
00877     }
00878 
00879   /* Union size has already been calculated.  */
00880   if (!current_stag->is_union)
00881     current_stag->size = size;
00882   /* Nested .structs don't get put in the stag table.  */
00883   if (current_stag->outer == NULL)
00884     {
00885       hash_insert (stag_hash, current_stag->name, current_stag);
00886       stag_add_field_symbols (current_stag, path,
00887                            S_GET_VALUE (current_stag->sym),
00888                            NULL, NULL);
00889     }
00890   current_stag = current_stag->outer;
00891 
00892   /* If this is a nested .struct/.union, add it as a field to the enclosing
00893      one.  otherwise, restore the section we were in.  */
00894   if (current_stag != NULL)
00895     {
00896       stag_add_field (current_stag, current_stag->inner->name,
00897                     S_GET_VALUE (current_stag->inner->sym),
00898                     current_stag->inner);
00899     }
00900   else
00901     subseg_set (stag_saved_seg, stag_saved_subseg);
00902 }
00903 
00904 /* [LABEL]      .tag    STAG
00905    Reference a structure within a structure, as a sized field with an optional
00906    label.
00907    If used outside of a .struct/.endstruct, overlays the given structure
00908    format on the existing allocated space.  */
00909 
00910 static void
00911 tic54x_tag (ignore)
00912      int ignore ATTRIBUTE_UNUSED;
00913 {
00914   char *name = input_line_pointer;
00915   int c = get_symbol_end ();
00916   struct stag *stag = (struct stag *) hash_find (stag_hash, name);
00917 
00918   if (!stag)
00919     {
00920       if (*name)
00921        as_bad (_("Unrecognized struct/union tag '%s'"), name);
00922       else
00923        as_bad (_(".tag requires a structure tag"));
00924       ignore_rest_of_line ();
00925       return;
00926     }
00927   if (line_label == NULL)
00928     {
00929       as_bad (_("Label required for .tag"));
00930       ignore_rest_of_line ();
00931       return;
00932     }
00933   else
00934     {
00935       char label[strlen (S_GET_NAME (line_label)) + 1];
00936 
00937       strcpy (label, S_GET_NAME (line_label));
00938       if (current_stag != NULL)
00939        stag_add_field (current_stag, label,
00940                      abs_section_offset - S_GET_VALUE (current_stag->sym),
00941                      stag);
00942       else
00943        {
00944          symbolS *sym = symbol_find (label);
00945 
00946          if (!sym)
00947            {
00948              as_bad (_(".tag target '%s' undefined"), label);
00949              ignore_rest_of_line ();
00950              return;
00951            }
00952          stag_add_field_symbols (stag, S_GET_NAME (sym),
00953                               S_GET_VALUE (stag->sym), sym, stag->name);
00954        }
00955     }
00956 
00957   /* Bump by the struct size, but only if we're within a .struct section.  */
00958   if (current_stag != NULL && !current_stag->is_union)
00959     abs_section_offset += stag->size;
00960 
00961   *input_line_pointer = c;
00962   demand_empty_rest_of_line ();
00963   line_label = NULL;
00964 }
00965 
00966 /* Handle all .byte, .char, .double, .field, .float, .half, .int, .long,
00967    .short, .string, .ubyte, .uchar, .uhalf, .uint, .ulong, .ushort, .uword,
00968    and .word.  */
00969 
00970 static void
00971 tic54x_struct_field (type)
00972      int type;
00973 {
00974   int size;
00975   int count = 1;
00976   int new_bitfield_offset = 0;
00977   int field_align = current_stag->current_bitfield_offset != 0;
00978   int longword_align = 0;
00979 
00980   SKIP_WHITESPACE ();
00981   if (!is_end_of_line[(int) *input_line_pointer])
00982     count = get_absolute_expression ();
00983 
00984   switch (type)
00985     {
00986     case 'b':
00987     case 'B':
00988     case 'c':
00989     case 'C':
00990     case 'h':
00991     case 'H':
00992     case 'i':
00993     case 'I':
00994     case 's':
00995     case 'S':
00996     case 'w':
00997     case 'W':
00998     case '*': /* String.  */
00999       size = 1;
01000       break;
01001     case 'f':
01002     case 'l':
01003     case 'L':
01004       longword_align = 1;
01005       size = 2;
01006       break;
01007     case '.': /* Bitfield.  */
01008       size = 0;
01009       if (count < 1 || count > 32)
01010        {
01011          as_bad (_(".field count '%d' out of range (1 <= X <= 32)"), count);
01012          ignore_rest_of_line ();
01013          return;
01014        }
01015       if (current_stag->current_bitfield_offset + count > 16)
01016        {
01017          /* Set the appropriate size and new field offset.  */
01018          if (count == 32)
01019            {
01020              size = 2;
01021              count = 1;
01022            }
01023          else if (count > 16)
01024            {
01025              size = 1;
01026              count = 1;
01027              new_bitfield_offset = count - 16;
01028            }
01029          else
01030            new_bitfield_offset = count;
01031        }
01032       else
01033        {
01034          field_align = 0;
01035          new_bitfield_offset = current_stag->current_bitfield_offset + count;
01036        }
01037       break;
01038     default:
01039       as_bad (_("Unrecognized field type '%c'"), type);
01040       ignore_rest_of_line ();
01041       return;
01042     }
01043 
01044   if (field_align)
01045     {
01046       /* Align to the actual starting position of the field.  */
01047       current_stag->current_bitfield_offset = 0;
01048       ++abs_section_offset;
01049     }
01050   /* Align to longword boundary.  */
01051   if (longword_align && (abs_section_offset & 0x1))
01052     ++abs_section_offset;
01053 
01054   if (line_label == NULL)
01055     {
01056       static int fieldno = 0;
01057       char fake[] = ".fake_fieldNNNNN";
01058 
01059       sprintf (fake, ".fake_field%d", fieldno++);
01060       stag_add_field (current_stag, fake,
01061                     abs_section_offset - S_GET_VALUE (current_stag->sym),
01062                     NULL);
01063     }
01064   else
01065     {
01066       char label[strlen (S_GET_NAME (line_label) + 1)];
01067 
01068       strcpy (label, S_GET_NAME (line_label));
01069       stag_add_field (current_stag, label,
01070                     abs_section_offset - S_GET_VALUE (current_stag->sym),
01071                     NULL);
01072     }
01073 
01074   if (current_stag->is_union)
01075     {
01076       /* Note we treat the element as if it were an array of COUNT.  */
01077       if (current_stag->size < (unsigned) size * count)
01078        current_stag->size = size * count;
01079     }
01080   else
01081     {
01082       abs_section_offset += (unsigned) size * count;
01083       current_stag->current_bitfield_offset = new_bitfield_offset;
01084     }
01085   line_label = NULL;
01086 }
01087 
01088 /* Handle .byte, .word. .int, .long and all variants.  */
01089 
01090 static void
01091 tic54x_cons (type)
01092      int type;
01093 {
01094   unsigned int c;
01095   int octets;
01096 
01097   /* If we're within a .struct construct, don't actually allocate space.  */
01098   if (current_stag != NULL)
01099     {
01100       tic54x_struct_field (type);
01101       return;
01102     }
01103 
01104 #ifdef md_flush_pending_output
01105   md_flush_pending_output ();
01106 #endif
01107 
01108   generate_lineno_debug ();
01109 
01110   /* Align long words to long word boundaries (4 octets).  */
01111   if (type == 'l' || type == 'L')
01112     {
01113       frag_align (2, 0, 2);
01114       /* If there's a label, assign it to the first allocated word.  */
01115       if (line_label != NULL)
01116        {
01117          symbol_set_frag (line_label, frag_now);
01118          S_SET_VALUE (line_label, frag_now_fix ());
01119        }
01120     }
01121 
01122   switch (type)
01123     {
01124     case 'l':
01125     case 'L':
01126     case 'x':
01127       octets = 4;
01128       break;
01129     case 'b':
01130     case 'B':
01131     case 'c':
01132     case 'C':
01133       octets = 1;
01134       break;
01135     default:
01136       octets = 2;
01137       break;
01138     }
01139 
01140   do
01141     {
01142       if (*input_line_pointer == '"')
01143        {
01144          input_line_pointer++;
01145          while (is_a_char (c = next_char_of_string ()))
01146            tic54x_emit_char (c);
01147          know (input_line_pointer[-1] == '\"');
01148        }
01149       else
01150        {
01151          expressionS exp;
01152 
01153          input_line_pointer = parse_expression (input_line_pointer, &exp);
01154          if (exp.X_op == O_constant)
01155            {
01156              offsetT value = exp.X_add_number;
01157              /* Truncate overflows.  */
01158              switch (octets)
01159               {
01160               case 1:
01161                 if ((value > 0 && value > 0xFF)
01162                     || (value < 0 && value < - 0x100))
01163                   as_warn ("Overflow in expression, truncated to 8 bits");
01164                 break;
01165               case 2:
01166                 if ((value > 0 && value > 0xFFFF)
01167                     || (value < 0 && value < - 0x10000))
01168                   as_warn ("Overflow in expression, truncated to 16 bits");
01169                 break;
01170               }
01171            }
01172          if (exp.X_op != O_constant && octets < 2)
01173            {
01174              /* Disallow .byte with a non constant expression that will
01175                require relocation.  */
01176              as_bad (_("Relocatable values require at least WORD storage"));
01177              ignore_rest_of_line ();
01178              return;
01179            }
01180 
01181          if (exp.X_op != O_constant
01182              && amode == c_mode
01183              && octets == 4)
01184            {
01185              /* FIXME -- at one point TI tools used to output REL16
01186                relocations, but I don't think the latest tools do at all
01187                The current tools output extended relocations regardless of
01188                the addressing mode (I actually think that ".c_mode" is
01189                totally ignored in the latest tools).  */
01190              amode = far_mode;
01191              emitting_long = 1;
01192              emit_expr (&exp, 4);
01193              emitting_long = 0;
01194              amode = c_mode;
01195            }
01196          else
01197            {
01198              emitting_long = octets == 4;
01199              emit_expr (&exp, (octets == 1) ? 2 : octets);
01200              emitting_long = 0;
01201            }
01202        }
01203     }
01204   while (*input_line_pointer++ == ',');
01205 
01206   input_line_pointer--;            /* Put terminator back into stream.  */
01207   demand_empty_rest_of_line ();
01208 }
01209 
01210 /* .global <symbol>[,...,<symbolN>]
01211    .def    <symbol>[,...,<symbolN>]
01212    .ref    <symbol>[,...,<symbolN>]
01213 
01214    These all identify global symbols.
01215 
01216    .def means the symbol is defined in the current module and can be accessed
01217    by other files.  The symbol should be placed in the symbol table.
01218 
01219    .ref means the symbol is used in the current module but defined in another
01220    module.  The linker is to resolve this symbol's definition at link time.
01221 
01222    .global should act as a .ref or .def, as needed.
01223 
01224    global, def and ref all have symbol storage classes of C_EXT.
01225 
01226    I can't identify any difference in how the "other" c54x assembler treats
01227    these, so we ignore the type here.  */
01228 
01229 void
01230 tic54x_global (type)
01231      int type;
01232 {
01233   char *name;
01234   int c;
01235   symbolS *symbolP;
01236 
01237   if (type == 'r')
01238     as_warn (_("Use of .def/.ref is deprecated.  Use .global instead"));
01239 
01240   ILLEGAL_WITHIN_STRUCT ();
01241 
01242   do
01243     {
01244       name = input_line_pointer;
01245       c = get_symbol_end ();
01246       symbolP = symbol_find_or_make (name);
01247 
01248       *input_line_pointer = c;
01249       S_SET_STORAGE_CLASS (symbolP, C_EXT);
01250       if (c == ',')
01251        {
01252          input_line_pointer++;
01253          if (is_end_of_line[(int) *input_line_pointer])
01254            c = *input_line_pointer;
01255        }
01256     }
01257   while (c == ',');
01258 
01259   demand_empty_rest_of_line ();
01260 }
01261 
01262 /* Remove the symbol from the local label hash lookup.  */
01263 
01264 static void
01265 tic54x_remove_local_label (key, value)
01266      const char *key;
01267      PTR value ATTRIBUTE_UNUSED;
01268 {
01269   PTR *elem = hash_delete (local_label_hash[macro_level], key);
01270   free (elem);
01271 }
01272 
01273 /* Reset all local labels.  */
01274 
01275 static void
01276 tic54x_clear_local_labels (ignored)
01277      int ignored ATTRIBUTE_UNUSED;
01278 {
01279   hash_traverse (local_label_hash[macro_level], tic54x_remove_local_label);
01280 }
01281 
01282 /* .text
01283    .data
01284    .sect "section name"
01285 
01286    Initialized section
01287    make sure local labels get cleared when changing sections
01288 
01289    ARG is 't' for text, 'd' for data, or '*' for a named section
01290 
01291    For compatibility, '*' sections are SEC_CODE if instructions are
01292    encountered, or SEC_DATA if not.
01293 */
01294 
01295 static void
01296 tic54x_sect (arg)
01297      int arg;
01298 {
01299   ILLEGAL_WITHIN_STRUCT ();
01300 
01301   /* Local labels are cleared when changing sections.  */
01302   tic54x_clear_local_labels (0);
01303 
01304   if (arg == 't')
01305     s_text (0);
01306   else if (arg == 'd')
01307     s_data (0);
01308   else
01309     {
01310       char *name = NULL;
01311       int len;
01312 
01313       /* If there are quotes, remove them.  */
01314       if (*input_line_pointer == '"')
01315        {
01316          name = demand_copy_C_string (&len);
01317          demand_empty_rest_of_line ();
01318          name = strcpy (xmalloc (len + 10), name);
01319        }
01320       else
01321        {
01322          int c;
01323          name = input_line_pointer;
01324          c = get_symbol_end ();
01325           len = strlen(name);
01326          name = strcpy (xmalloc (len + 10), name);
01327          *input_line_pointer = c;
01328          demand_empty_rest_of_line ();
01329        }
01330       /* Make sure all named initialized sections flagged properly.  If we
01331          encounter instructions, we'll flag it with SEC_CODE as well.  */
01332       strcat (name, ",\"w\"\n");
01333       input_scrub_insert_line (name);
01334       obj_coff_section (0);
01335 
01336       /* If there was a line label, make sure that it gets assigned the proper
01337         section.  This is for compatibility, even though the actual behavior
01338         is not explicitly defined.  For consistency, we make .sect behave
01339         like .usect, since that is probably what people expect.  */
01340       if (line_label != NULL)
01341        {
01342          S_SET_SEGMENT (line_label, now_seg);
01343          symbol_set_frag (line_label, frag_now);
01344          S_SET_VALUE (line_label, frag_now_fix ());
01345          if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
01346            S_SET_STORAGE_CLASS (line_label, C_LABEL);
01347        }
01348     }
01349 }
01350 
01351 /* [symbol] .space space_in_bits
01352    [symbol] .bes space_in_bits
01353    BES puts the symbol at the *last* word allocated
01354 
01355    cribbed from s_space.  */
01356 
01357 static void
01358 tic54x_space (arg)
01359      int arg;
01360 {
01361   expressionS exp;
01362   char *p = 0;
01363   int octets = 0;
01364   long words;
01365   int bits_per_byte = (OCTETS_PER_BYTE * 8);
01366   int bit_offset = 0;
01367   symbolS *label = line_label;
01368   int bes = arg;
01369 
01370   ILLEGAL_WITHIN_STRUCT ();
01371 
01372 #ifdef md_flush_pending_output
01373   md_flush_pending_output ();
01374 #endif
01375 
01376   /* Read the bit count.  */
01377   expression (&exp);
01378 
01379   /* Some expressions are unresolvable until later in the assembly pass;
01380      postpone until relaxation/fixup.  we also have to postpone if a previous
01381      partial allocation has not been completed yet.  */
01382   if (exp.X_op != O_constant || frag_bit_offset (frag_now, now_seg) == -1)
01383     {
01384       struct bit_info *bi = xmalloc (sizeof (struct bit_info));
01385       char *p;
01386 
01387       bi->seg = now_seg;
01388       bi->type = bes;
01389       bi->sym = label;
01390       p = frag_var (rs_machine_dependent,
01391                   65536 * 2, 1, (relax_substateT) 0,
01392                   make_expr_symbol (&exp), (offsetT) 0,
01393                   (char *) bi);
01394       if (p)
01395        *p = 0;
01396 
01397       return;
01398     }
01399 
01400   /* Reduce the required size by any bit offsets currently left over
01401      from a previous .space/.bes/.field directive.  */
01402   bit_offset = frag_now->tc_frag_data;
01403   if (bit_offset != 0 && bit_offset < 16)
01404     {
01405       int spare_bits = bits_per_byte - bit_offset;
01406 
01407       if (spare_bits >= exp.X_add_number)
01408        {
01409          /* Don't have to do anything; sufficient bits have already been
01410             allocated; just point the label to the right place.  */
01411          if (label != NULL)
01412            {
01413              symbol_set_frag (label, frag_now);
01414              S_SET_VALUE (label, frag_now_fix () - 1);
01415              label = NULL;
01416            }
01417          frag_now->tc_frag_data += exp.X_add_number;
01418          goto getout;
01419        }
01420       exp.X_add_number -= spare_bits;
01421       /* Set the label to point to the first word allocated, which in this
01422         case is the previous word, which was only partially filled.  */
01423       if (!bes && label != NULL)
01424        {
01425          symbol_set_frag (label, frag_now);
01426          S_SET_VALUE (label, frag_now_fix () - 1);
01427          label = NULL;
01428        }
01429     }
01430   /* Convert bits to bytes/words and octets, rounding up.  */
01431   words = ((exp.X_add_number + bits_per_byte - 1) / bits_per_byte);
01432   /* How many do we have left over?  */
01433   bit_offset = exp.X_add_number % bits_per_byte;
01434   octets = words * OCTETS_PER_BYTE;
01435   if (octets < 0)
01436     {
01437       as_warn (_(".space/.bes repeat count is negative, ignored"));
01438       goto getout;
01439     }
01440   else if (octets == 0)
01441     {
01442       as_warn (_(".space/.bes repeat count is zero, ignored"));
01443       goto getout;
01444     }
01445 
01446   /* If we are in the absolute section, just bump the offset.  */
01447   if (now_seg == absolute_section)
01448     {
01449       abs_section_offset += words;
01450       if (bes && label != NULL)
01451        S_SET_VALUE (label, abs_section_offset - 1);
01452       frag_now->tc_frag_data = bit_offset;
01453       goto getout;
01454     }
01455 
01456   if (!need_pass_2)
01457     p = frag_var (rs_fill, 1, 1,
01458                 (relax_substateT) 0, (symbolS *) 0,
01459                 (offsetT) octets, (char *) 0);
01460 
01461   /* Make note of how many bits of this word we've allocated so far.  */
01462   frag_now->tc_frag_data = bit_offset;
01463 
01464   /* .bes puts label at *last* word allocated.  */
01465   if (bes && label != NULL)
01466     {
01467       symbol_set_frag (label, frag_now);
01468       S_SET_VALUE (label, frag_now_fix () - 1);
01469     }
01470 
01471   if (p)
01472     *p = 0;
01473 
01474  getout:
01475 
01476   demand_empty_rest_of_line ();
01477 }
01478 
01479 /* [symbol] .usect "section-name", size-in-words
01480                  [, [blocking-flag] [, alignment-flag]]
01481 
01482    Uninitialized section.
01483    Non-zero blocking means that if the section would cross a page (128-word)
01484    boundary, it will be page-aligned.
01485    Non-zero alignment aligns on a longword boundary.
01486 
01487    Has no effect on the current section.  */
01488 
01489 static void
01490 tic54x_usect (x)
01491      int x ATTRIBUTE_UNUSED;
01492 {
01493   char c;
01494   char *name;
01495   char *section_name;
01496   char *p;
01497   segT seg;
01498   int size, blocking_flag, alignment_flag;
01499   segT current_seg;
01500   subsegT current_subseg;
01501   flagword flags;
01502 
01503   ILLEGAL_WITHIN_STRUCT ();
01504 
01505   current_seg = now_seg;    /* Save current seg.  */
01506   current_subseg = now_subseg;     /* Save current subseg.  */
01507 
01508   if (*input_line_pointer == '"')
01509     input_line_pointer++;
01510   section_name = input_line_pointer;
01511   c = get_symbol_end ();    /* Get terminator.  */
01512   input_line_pointer++;            /* Skip null symbol terminator.  */
01513   name = xmalloc (input_line_pointer - section_name + 1);
01514   strcpy (name, section_name);
01515 
01516   if (*input_line_pointer == ',')
01517     ++input_line_pointer;
01518   else if (c != ',')
01519     {
01520       as_bad (_("Missing size argument"));
01521       ignore_rest_of_line ();
01522       return;
01523     }
01524 
01525   size = get_absolute_expression ();
01526 
01527   /* Read a possibly present third argument (blocking flag).  */
01528   if (*input_line_pointer == ',')
01529     {
01530       ++input_line_pointer;
01531       if (*input_line_pointer != ',')
01532        blocking_flag = get_absolute_expression ();
01533       else
01534        blocking_flag = 0;
01535 
01536       /* Read a possibly present fourth argument (alignment flag).  */
01537       if (*input_line_pointer == ',')
01538        {
01539          ++input_line_pointer;
01540          alignment_flag = get_absolute_expression ();
01541        }
01542       else
01543        alignment_flag = 0;
01544     }
01545   else
01546     blocking_flag = alignment_flag = 0;
01547 
01548   seg = subseg_new (name, 0);
01549   flags = bfd_get_section_flags (stdoutput, seg) | SEC_ALLOC;
01550 
01551   if (alignment_flag)
01552     {
01553       /* s_align eats end of line; restore it.  */
01554       s_align_bytes (4);
01555       --input_line_pointer;
01556     }
01557 
01558   if (line_label != NULL)
01559     {
01560       S_SET_SEGMENT (line_label, seg);
01561       symbol_set_frag (line_label, frag_now);
01562       S_SET_VALUE (line_label, frag_now_fix ());
01563       /* Set scl to label, since that's what TI does.  */
01564       if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
01565        S_SET_STORAGE_CLASS (line_label, C_LABEL);
01566     }
01567 
01568   seg_info (seg)->bss = 1;  /* Uninitialized data.  */
01569 
01570   p = frag_var (rs_fill, 1, 1,
01571               (relax_substateT) 0, (symbolS *) line_label,
01572               size * OCTETS_PER_BYTE, (char *) 0);
01573   *p = 0;
01574 
01575   if (blocking_flag)
01576     flags |= SEC_TIC54X_BLOCK;
01577 
01578   if (!bfd_set_section_flags (stdoutput, seg, flags))
01579     as_warn ("Error setting flags for \"%s\": %s", name,
01580             bfd_errmsg (bfd_get_error ()));
01581 
01582   subseg_set (current_seg, current_subseg);      /* Restore current seg.  */
01583   demand_empty_rest_of_line ();
01584 }
01585 
01586 static enum cpu_version
01587 lookup_version (ver)
01588      const char *ver;
01589 {
01590   enum cpu_version version = VNONE;
01591 
01592   if (ver[0] == '5' && ver[1] == '4')
01593     {
01594       if (strlen (ver) == 3
01595          && (ver[2] == '1' || ver[2] == '2' || ver[2] == '3'
01596              || ver[2] == '5' || ver[2] == '8' || ver[2] == '9'))
01597        version = ver[2] - '0';
01598       else if (strlen (ver) == 5
01599               && TOUPPER (ver[3]) == 'L'
01600               && TOUPPER (ver[4]) == 'P'
01601               && (ver[2] == '5' || ver[2] == '6'))
01602        version = ver[2] - '0' + 10;
01603     }
01604 
01605   return version;
01606 }
01607 
01608 static void
01609 set_cpu (version)
01610      enum cpu_version version;
01611 {
01612   cpu = version;
01613   if (version == V545LP || version == V546LP)
01614     {
01615       symbolS *symbolP = symbol_new ("__allow_lp", absolute_section,
01616                                  (valueT) 1, &zero_address_frag);
01617       SF_SET_LOCAL (symbolP);
01618       symbol_table_insert (symbolP);
01619     }
01620 }
01621 
01622 /* .version cpu-version
01623    cpu-version may be one of the following:
01624    541
01625    542
01626    543
01627    545
01628    545LP
01629    546LP
01630    548
01631    549
01632 
01633    This is for compatibility only.  It currently has no affect on assembly.  */
01634 static int cpu_needs_set = 1;
01635 
01636 static void
01637 tic54x_version (x)
01638      int x ATTRIBUTE_UNUSED;
01639 {
01640   enum cpu_version version = VNONE;
01641   enum cpu_version old_version = cpu;
01642   int c;
01643   char *ver;
01644 
01645   ILLEGAL_WITHIN_STRUCT ();
01646 
01647   SKIP_WHITESPACE ();
01648   ver = input_line_pointer;
01649   while (!is_end_of_line[(int) *input_line_pointer])
01650     ++input_line_pointer;
01651   c = *input_line_pointer;
01652   *input_line_pointer = 0;
01653 
01654   version = lookup_version (ver);
01655 
01656   if (cpu != VNONE && cpu != version)
01657     as_warn (_("CPU version has already been set"));
01658 
01659   if (version == VNONE)
01660     {
01661       as_bad (_("Unrecognized version '%s'"), ver);
01662       ignore_rest_of_line ();
01663       return;
01664     }
01665   else if (assembly_begun && version != old_version)
01666     {
01667       as_bad (_("Changing of CPU version on the fly not supported"));
01668       ignore_rest_of_line ();
01669       return;
01670     }
01671 
01672   set_cpu (version);
01673 
01674   *input_line_pointer = c;
01675   demand_empty_rest_of_line ();
01676 }
01677 
01678 /* 'f' = float, 'x' = xfloat, 'd' = double, 'l' = ldouble.  */
01679 
01680 static void
01681 tic54x_float_cons (type)
01682      int type;
01683 {
01684   if (current_stag != 0)
01685     tic54x_struct_field ('f');
01686 
01687 #ifdef md_flush_pending_output
01688   md_flush_pending_output ();
01689 #endif
01690 
01691   /* Align to long word boundary (4 octets) unless it's ".xfloat".  */
01692   if (type != 'x')
01693     {
01694       frag_align (2, 0, 2);
01695       /* If there's a label, assign it to the first allocated word.  */
01696       if (line_label != NULL)
01697        {
01698          symbol_set_frag (line_label, frag_now);
01699          S_SET_VALUE (line_label, frag_now_fix ());
01700        }
01701     }
01702 
01703   float_cons ('f');
01704 }
01705 
01706 /* The argument is capitalized if it should be zero-terminated
01707    's' is normal string with upper 8-bits zero-filled, 'p' is packed.
01708    Code copied from stringer, and slightly modified so that strings are packed
01709    and encoded into the correct octets.  */
01710 
01711 static void
01712 tic54x_stringer (type)
01713      int type;
01714 {
01715   unsigned int c;
01716   char *start;
01717   int append_zero = type == 'S' || type == 'P';
01718   int packed = type == 'p' || type == 'P';
01719   int last_char = -1; /* Packed strings need two bytes at a time to encode.  */
01720 
01721   if (current_stag != NULL)
01722     {
01723       tic54x_struct_field ('*');
01724       return;
01725     }
01726 
01727 #ifdef md_flush_pending_output
01728   md_flush_pending_output ();
01729 #endif
01730 
01731   c = ',';                  /* Do loop.  */
01732   while (c == ',')
01733     {
01734       SKIP_WHITESPACE ();
01735       switch (*input_line_pointer)
01736        {
01737        default:
01738          {
01739            unsigned short value = get_absolute_expression ();
01740            FRAG_APPEND_1_CHAR ( value       & 0xFF);
01741            FRAG_APPEND_1_CHAR ((value >> 8) & 0xFF);
01742            break;
01743          }
01744        case '\"':
01745          ++input_line_pointer;     /* -> 1st char of string.  */
01746          start = input_line_pointer;
01747          while (is_a_char (c = next_char_of_string ()))
01748            {
01749              if (!packed)
01750               {
01751                 FRAG_APPEND_1_CHAR (c);
01752                 FRAG_APPEND_1_CHAR (0);
01753               }
01754              else
01755               {
01756                 /* Packed strings are filled MS octet first.  */
01757                 if (last_char == -1)
01758                   last_char = c;
01759                 else
01760                   {
01761                     FRAG_APPEND_1_CHAR (c);
01762                     FRAG_APPEND_1_CHAR (last_char);
01763                     last_char = -1;
01764                   }
01765               }
01766            }
01767          if (append_zero)
01768            {
01769              if (packed && last_char != -1)
01770               {
01771                 FRAG_APPEND_1_CHAR (0);
01772                 FRAG_APPEND_1_CHAR (last_char);
01773                 last_char = -1;
01774               }
01775              else
01776               {
01777                 FRAG_APPEND_1_CHAR (0);
01778                 FRAG_APPEND_1_CHAR (0);
01779               }
01780            }
01781          know (input_line_pointer[-1] == '\"');
01782          break;
01783        }
01784       SKIP_WHITESPACE ();
01785       c = *input_line_pointer;
01786       if (!is_end_of_line[c])
01787        ++input_line_pointer;
01788     }
01789 
01790   /* Finish up any leftover packed string.  */
01791   if (packed && last_char != -1)
01792     {
01793       FRAG_APPEND_1_CHAR (0);
01794       FRAG_APPEND_1_CHAR (last_char);
01795     }
01796   demand_empty_rest_of_line ();
01797 }
01798 
01799 static void
01800 tic54x_p2align (arg)
01801      int arg ATTRIBUTE_UNUSED;
01802 {
01803   as_bad (_("p2align not supported on this target"));
01804 }
01805 
01806 static void
01807 tic54x_align_words (arg)
01808      int arg;
01809 {
01810   /* Only ".align" with no argument is allowed within .struct/.union.  */
01811   int count = arg;
01812 
01813   if (!is_end_of_line[(int) *input_line_pointer])
01814     {
01815       if (arg == 2)
01816        as_warn (_("Argument to .even ignored"));
01817       else
01818        count = get_absolute_expression ();
01819     }
01820 
01821   if (current_stag != NULL && arg == 128)
01822     {
01823       if (current_stag->current_bitfield_offset != 0)
01824        {
01825          current_stag->current_bitfield_offset = 0;
01826          ++abs_section_offset;
01827        }
01828       demand_empty_rest_of_line ();
01829       return;
01830     }
01831 
01832   ILLEGAL_WITHIN_STRUCT ();
01833 
01834   s_align_bytes (count << 1);
01835 }
01836 
01837 /* Initialize multiple-bit fields withing a single word of memory.  */
01838 
01839 static void
01840 tic54x_field (ignore)
01841      int ignore ATTRIBUTE_UNUSED;
01842 {
01843   expressionS exp;
01844   int size = 16;
01845   char *p;
01846   valueT value;
01847   symbolS *label = line_label;
01848 
01849   if (current_stag != NULL)
01850     {
01851       tic54x_struct_field ('.');
01852       return;
01853     }
01854 
01855   input_line_pointer = parse_expression (input_line_pointer, &exp);
01856 
01857   if (*input_line_pointer == ',')
01858     {
01859       ++input_line_pointer;
01860       size = get_absolute_expression ();
01861       if (size < 1 || size > 32)
01862        {
01863          as_bad (_("Invalid field size, must be from 1 to 32"));
01864          ignore_rest_of_line ();
01865          return;
01866        }
01867     }
01868 
01869   /* Truncate values to the field width.  */
01870   if (exp.X_op != O_constant)
01871     {
01872       /* If the expression value is relocatable, the field size *must*
01873          be 16.  */
01874       if (size != 16)
01875        {
01876          as_bad (_("field size must be 16 when value is relocatable"));
01877          ignore_rest_of_line ();
01878          return;
01879        }
01880 
01881       frag_now->tc_frag_data = 0;
01882       emit_expr (&exp, 2);
01883     }
01884   else
01885     {
01886       unsigned long fmask = (size == 32) ? 0xFFFFFFFF : (1ul << size) - 1;
01887 
01888       value = exp.X_add_number;
01889       exp.X_add_number &= fmask;
01890       if (value != (valueT) exp.X_add_number)
01891        as_warn (_("field value truncated"));
01892       value = exp.X_add_number;
01893       /* Bits are stored MS first.  */
01894       while (size >= 16)
01895        {
01896          frag_now->tc_frag_data = 0;
01897          p = frag_more (2);
01898          md_number_to_chars (p, (value >> (size - 16)) & 0xFFFF, 2);
01899          size -= 16;
01900        }
01901       if (size > 0)
01902        {
01903          int bit_offset = frag_bit_offset (frag_now, now_seg);
01904 
01905          fragS *alloc_frag = bit_offset_frag (frag_now, now_seg);
01906          if (bit_offset == -1)
01907            {
01908              struct bit_info *bi = xmalloc (sizeof (struct bit_info));
01909              /* We don't know the previous offset at this time, so store the
01910                info we need and figure it out later.  */
01911              expressionS size_exp;
01912 
01913              size_exp.X_op = O_constant;
01914              size_exp.X_add_number = size;
01915              bi->seg = now_seg;
01916              bi->type = TYPE_FIELD;
01917              bi->value = value;
01918              p = frag_var (rs_machine_dependent,
01919                          4, 1, (relax_substateT) 0,
01920                          make_expr_symbol (&size_exp), (offsetT) 0,
01921                          (char *) bi);
01922              goto getout;
01923            }
01924          else if (bit_offset == 0 || bit_offset + size > 16)
01925            {
01926              /* Align a new field.  */
01927              p = frag_more (2);
01928              frag_now->tc_frag_data = 0;
01929              alloc_frag = frag_now;
01930            }
01931          else
01932            {
01933              /* Put the new value entirely within the existing one.  */
01934              p = alloc_frag == frag_now ?
01935               frag_now->fr_literal + frag_now_fix_octets () - 2 :
01936               alloc_frag->fr_literal;
01937              if (label != NULL)
01938               {
01939                 symbol_set_frag (label, alloc_frag);
01940                 if (alloc_frag == frag_now)
01941                   S_SET_VALUE (label, frag_now_fix () - 1);
01942                 label = NULL;
01943               }
01944            }
01945          value <<= 16 - alloc_frag->tc_frag_data - size;
01946 
01947          /* OR in existing value.  */
01948          if (alloc_frag->tc_frag_data)
01949            value |= ((unsigned short) p[1] << 8) | p[0];
01950          md_number_to_chars (p, value, 2);
01951          alloc_frag->tc_frag_data += size;
01952          if (alloc_frag->tc_frag_data == 16)
01953            alloc_frag->tc_frag_data = 0;
01954        }
01955     }
01956  getout:
01957   demand_empty_rest_of_line ();
01958 }
01959 
01960 /* Ideally, we want to check SEC_LOAD and SEC_HAS_CONTENTS, but those aren't
01961    available yet.  seg_info ()->bss is the next best thing.  */
01962 
01963 static int
01964 tic54x_initialized_section (seg)
01965      segT seg;
01966 {
01967   return !seg_info (seg)->bss;
01968 }
01969 
01970 /* .clink ["section name"]
01971 
01972    Marks the section as conditionally linked (link only if contents are
01973    referenced elsewhere.
01974    Without a name, refers to the current initialized section.
01975    Name is required for uninitialized sections.  */
01976 
01977 static void
01978 tic54x_clink (ignored)
01979      int ignored ATTRIBUTE_UNUSED;
01980 {
01981   segT seg = now_seg;
01982 
01983   ILLEGAL_WITHIN_STRUCT ();
01984 
01985   if (*input_line_pointer == '\"')
01986     {
01987       char *section_name = ++input_line_pointer;
01988       char *name;
01989 
01990       while (is_a_char (next_char_of_string ()))
01991        ;
01992       know (input_line_pointer[-1] == '\"');
01993       input_line_pointer[-1] = 0;
01994       name = xmalloc (input_line_pointer - section_name + 1);
01995       strcpy (name, section_name);
01996 
01997       seg = bfd_get_section_by_name (stdoutput, name);
01998       if (seg == NULL)
01999        {
02000          as_bad (_("Unrecognized section '%s'"), section_name);
02001          ignore_rest_of_line ();
02002          return;
02003        }
02004     }
02005   else
02006     {
02007       if (!tic54x_initialized_section (seg))
02008        {
02009          as_bad (_("Current section is unitialized, "
02010                   "section name required for .clink"));
02011          ignore_rest_of_line ();
02012          return;
02013        }
02014     }
02015 
02016   seg->flags |= SEC_TIC54X_CLINK;
02017 
02018   demand_empty_rest_of_line ();
02019 }
02020 
02021 /* Change the default include directory to be the current source file's
02022    directory, instead of the current working directory.  If DOT is non-zero,
02023    set to "." instead.  */
02024 
02025 static void
02026 tic54x_set_default_include (dot)
02027      int dot;
02028 {
02029   char *dir = ".";
02030   char *tmp = NULL;
02031 
02032   if (!dot)
02033     {
02034       char *curfile;
02035       unsigned lineno;
02036 
02037       as_where (&curfile, &lineno);
02038       dir = strcpy (xmalloc (strlen (curfile) + 1), curfile);
02039       tmp = strrchr (dir, '/');
02040     }
02041   if (tmp != NULL)
02042     {
02043       int len;
02044 
02045       *tmp = '\0';
02046       len = strlen (dir);
02047       if (include_dir_count == 0)
02048        {
02049          include_dirs = (char **) xmalloc (sizeof (*include_dirs));
02050          include_dir_count = 1;
02051        }
02052       include_dirs[0] = dir;
02053       if (len > include_dir_maxlen)
02054        include_dir_maxlen = len;
02055     }
02056   else if (include_dirs != NULL)
02057     include_dirs[0] = ".";
02058 }
02059 
02060 /* .include "filename" | filename
02061    .copy    "filename" | filename
02062 
02063    FIXME 'include' file should be omitted from any output listing,
02064      'copy' should be included in any output listing
02065    FIXME -- prevent any included files from changing listing (compat only)
02066    FIXME -- need to include source file directory in search path; what's a
02067       good way to do this?
02068 
02069    Entering/exiting included/copied file clears all local labels.  */
02070 
02071 static void
02072 tic54x_include (ignored)
02073      int ignored ATTRIBUTE_UNUSED;
02074 {
02075   char newblock[] = " .newblock\n";
02076   char *filename;
02077   char *input;
02078   int len, c = -1;
02079 
02080   ILLEGAL_WITHIN_STRUCT ();
02081 
02082   SKIP_WHITESPACE ();
02083 
02084   if (*input_line_pointer == '"')
02085     {
02086       filename = demand_copy_C_string (&len);
02087       demand_empty_rest_of_line ();
02088     }
02089   else
02090     {
02091       filename = input_line_pointer;
02092       while (!is_end_of_line[(int) *input_line_pointer])
02093        ++input_line_pointer;
02094       c = *input_line_pointer;
02095       *input_line_pointer = '\0';
02096       filename = strcpy (xmalloc (strlen (filename) + 1), filename);
02097       *input_line_pointer = c;
02098       demand_empty_rest_of_line ();
02099     }
02100   /* Insert a partial line with the filename (for the sake of s_include)
02101      and a .newblock.
02102      The included file will be inserted before the newblock, so that the
02103      newblock is executed after the included file is processed.  */
02104   input = xmalloc (sizeof (newblock) + strlen (filename) + 4);
02105   sprintf (input, "\"%s\"\n%s", filename, newblock);
02106   input_scrub_insert_line (input);
02107 
02108   tic54x_clear_local_labels (0);
02109 
02110   tic54x_set_default_include (0);
02111 
02112   s_include (0);
02113 }
02114 
02115 static void
02116 tic54x_message (type)
02117      int type;
02118 {
02119   char *msg;
02120   char c;
02121   int len;
02122 
02123   ILLEGAL_WITHIN_STRUCT ();
02124 
02125   if (*input_line_pointer == '"')
02126     msg = demand_copy_C_string (&len);
02127   else
02128     {
02129       msg = input_line_pointer;
02130       while (!is_end_of_line[(int) *input_line_pointer])
02131        ++input_line_pointer;
02132       c = *input_line_pointer;
02133       *input_line_pointer = 0;
02134       msg = strcpy (xmalloc (strlen (msg) + 1), msg);
02135       *input_line_pointer = c;
02136     }
02137 
02138   switch (type)
02139     {
02140     case 'm':
02141       as_tsktsk ("%s", msg);
02142       break;
02143     case 'w':
02144       as_warn ("%s", msg);
02145       break;
02146     case 'e':
02147       as_bad ("%s", msg);
02148       break;
02149     }
02150 
02151   demand_empty_rest_of_line ();
02152 }
02153 
02154 /* .label <symbol>
02155    Define a special symbol that refers to the loadtime address rather than the
02156    runtime address within the current section.
02157 
02158    This symbol gets a special storage class so that when it is resolved, it is
02159    resolved relative to the load address (lma) of the section rather than the
02160    run address (vma).  */
02161 
02162 static void
02163 tic54x_label (ignored)
02164      int ignored ATTRIBUTE_UNUSED;
02165 {
02166   char *name = input_line_pointer;
02167   symbolS *symbolP;
02168   int c;
02169 
02170   ILLEGAL_WITHIN_STRUCT ();
02171 
02172   c = get_symbol_end ();
02173   symbolP = colon (name);
02174   S_SET_STORAGE_CLASS (symbolP, C_STATLAB);
02175 
02176   *input_line_pointer = c;
02177   demand_empty_rest_of_line ();
02178 }
02179 
02180 /* .mmregs
02181    Install all memory-mapped register names into the symbol table as
02182    absolute local symbols.  */
02183 
02184 static void
02185 tic54x_mmregs (ignored)
02186      int ignored ATTRIBUTE_UNUSED;
02187 {
02188   symbol *sym;
02189 
02190   ILLEGAL_WITHIN_STRUCT ();
02191 
02192   for (sym = (symbol *) mmregs; sym->name; sym++)
02193     {
02194       symbolS *symbolP = symbol_new (sym->name, absolute_section,
02195                                  (valueT) sym->value, &zero_address_frag);
02196       SF_SET_LOCAL (symbolP);
02197       symbol_table_insert (symbolP);
02198     }
02199 }
02200 
02201 /* .loop [count]
02202    Count defaults to 1024.  */
02203 
02204 static void
02205 tic54x_loop (count)
02206      int count;
02207 {
02208   ILLEGAL_WITHIN_STRUCT ();
02209 
02210   SKIP_WHITESPACE ();
02211   if (!is_end_of_line[(int) *input_line_pointer])
02212     count = get_absolute_expression ();
02213 
02214   do_repeat (count, "LOOP", "ENDLOOP");
02215 }
02216 
02217 /* Normally, endloop gets eaten by the preceding loop.  */
02218 
02219 static void
02220 tic54x_endloop (ignore)
02221      int ignore ATTRIBUTE_UNUSED;
02222 {
02223   as_bad (_("ENDLOOP without corresponding LOOP"));
02224   ignore_rest_of_line ();
02225 }
02226 
02227 /* .break [condition].  */
02228 
02229 static void
02230 tic54x_break (ignore)
02231      int ignore ATTRIBUTE_UNUSED;
02232 {
02233   int cond = 1;
02234 
02235   ILLEGAL_WITHIN_STRUCT ();
02236 
02237   SKIP_WHITESPACE ();
02238   if (!is_end_of_line[(int) *input_line_pointer])
02239     cond = get_absolute_expression ();
02240 
02241   if (cond)
02242     end_repeat (substitution_line ? 1 : 0);
02243 }
02244 
02245 static void
02246 set_address_mode (mode)
02247      int mode;
02248 {
02249   amode = mode;
02250   if (mode == far_mode)
02251     {
02252       symbolS *symbolP = symbol_new ("__allow_far", absolute_section,
02253                                  (valueT) 1, &zero_address_frag);
02254       SF_SET_LOCAL (symbolP);
02255       symbol_table_insert (symbolP);
02256     }
02257 }
02258 
02259 static int address_mode_needs_set = 1;
02260 
02261 static void
02262 tic54x_address_mode (mode)
02263      int mode;
02264 {
02265   if (assembly_begun && amode != (unsigned) mode)
02266     {
02267       as_bad (_("Mixing of normal and extended addressing not supported"));
02268       ignore_rest_of_line ();
02269       return;
02270     }
02271   if (mode == far_mode && cpu != VNONE && cpu != V548 && cpu != V549)
02272     {
02273       as_bad (_("Extended addressing not supported on the specified CPU"));
02274       ignore_rest_of_line ();
02275       return;
02276     }
02277 
02278   set_address_mode (mode);
02279   demand_empty_rest_of_line ();
02280 }
02281 
02282 /* .sblock "section"|section [,...,"section"|section]
02283    Designate initialized sections for blocking.  */
02284 
02285 static void
02286 tic54x_sblock (ignore)
02287      int ignore ATTRIBUTE_UNUSED;
02288 {
02289   int c = ',';
02290 
02291   ILLEGAL_WITHIN_STRUCT ();
02292 
02293   while (c == ',')
02294     {
02295       segT seg;
02296       char *name;
02297 
02298       if (*input_line_pointer == '"')
02299        {
02300          int len;
02301 
02302          name = demand_copy_C_string (&len);
02303        }
02304       else
02305        {
02306          char *section_name = input_line_pointer;
02307 
02308          c = get_symbol_end ();
02309          name = xmalloc (strlen (section_name) + 1);
02310          strcpy (name, section_name);
02311          *input_line_pointer = c;
02312        }
02313 
02314       seg = bfd_get_section_by_name (stdoutput, name);
02315       if (seg == NULL)
02316        {
02317          as_bad (_("Unrecognized section '%s'"), name);
02318          ignore_rest_of_line ();
02319          return;
02320        }
02321       else if (!tic54x_initialized_section (seg))
02322        {
02323          as_bad (_(".sblock may be used for initialized sections only"));
02324          ignore_rest_of_line ();
02325          return;
02326        }
02327       seg->flags |= SEC_TIC54X_BLOCK;
02328 
02329       c = *input_line_pointer;
02330       if (!is_end_of_line[(int) c])
02331        ++input_line_pointer;
02332     }
02333 
02334   demand_empty_rest_of_line ();
02335 }
02336 
02337 /* symbol .set value
02338    symbol .equ value
02339 
02340    value must be defined externals; no forward-referencing allowed
02341    symbols assigned with .set/.equ may not be redefined.  */
02342 
02343 static void
02344 tic54x_set (ignore)
02345      int ignore ATTRIBUTE_UNUSED;
02346 {
02347   symbolS *symbolP;
02348   char *name;
02349 
02350   ILLEGAL_WITHIN_STRUCT ();
02351 
02352   if (!line_label)
02353     {
02354       as_bad (_("Symbol missing for .set/.equ"));
02355       ignore_rest_of_line ();
02356       return;
02357     }
02358   name = xstrdup (S_GET_NAME (line_label));
02359   line_label = NULL;
02360   if ((symbolP = symbol_find (name)) == NULL
02361       && (symbolP = md_undefined_symbol (name)) == NULL)
02362     {
02363       symbolP = symbol_new (name, absolute_section, 0, &zero_address_frag);
02364       S_SET_STORAGE_CLASS (symbolP, C_STAT);
02365     }
02366   free (name);
02367   S_SET_DATA_TYPE (symbolP, T_INT);
02368   S_SET_SEGMENT (symbolP, absolute_section);
02369   symbol_table_insert (symbolP);
02370   pseudo_set (symbolP);
02371   demand_empty_rest_of_line ();
02372 }
02373 
02374 /* .fclist
02375    .fcnolist
02376    List false conditional blocks.  */
02377 
02378 static void
02379 tic54x_fclist (show)
02380      int show;
02381 {
02382   if (show)
02383     listing &= ~LISTING_NOCOND;
02384   else
02385     listing |= LISTING_NOCOND;
02386   demand_empty_rest_of_line ();
02387 }
02388 
02389 static void
02390 tic54x_sslist (show)
02391      int show;
02392 {
02393   ILLEGAL_WITHIN_STRUCT ();
02394 
02395   listing_sslist = show;
02396 }
02397 
02398 /* .var SYM[,...,SYMN]
02399    Define a substitution string to be local to a macro.  */
02400 
02401 static void
02402 tic54x_var (ignore)
02403      int ignore ATTRIBUTE_UNUSED;
02404 {
02405   static char empty[] = "";
02406   char *name;
02407   int c;
02408 
02409   ILLEGAL_WITHIN_STRUCT ();
02410 
02411   if (macro_level == 0)
02412     {
02413       as_bad (_(".var may only be used within a macro definition"));
02414       ignore_rest_of_line ();
02415       return;
02416     }
02417   do
02418     {
02419       if (!ISALPHA (*input_line_pointer))
02420        {
02421          as_bad (_("Substitution symbols must begin with a letter"));
02422          ignore_rest_of_line ();
02423          return;
02424        }
02425       name = input_line_pointer;
02426       c = get_symbol_end ();
02427       /* .var symbols start out with a null string.  */
02428       name = strcpy (xmalloc (strlen (name) + 1), name);
02429       hash_insert (subsym_hash[macro_level], name, empty);
02430       *input_line_pointer = c;
02431       if (c == ',')
02432        {
02433          ++input_line_pointer;
02434          if (is_end_of_line[(int) *input_line_pointer])
02435            c = *input_line_pointer;
02436        }
02437     }
02438   while (c == ',');
02439 
02440   demand_empty_rest_of_line ();
02441 }
02442 
02443 /* .mlib <macro library filename>
02444 
02445    Macro libraries are archived (standard AR-format) text macro definitions
02446    Expand the file and include it.
02447 
02448    FIXME need to try the source file directory as well.  */
02449 
02450 static void
02451 tic54x_mlib (ignore)
02452      int ignore ATTRIBUTE_UNUSED;
02453 {
02454   char *filename;
02455   char *path;
02456   int len, i;
02457   bfd *abfd, *mbfd;
02458 
02459   ILLEGAL_WITHIN_STRUCT ();
02460 
02461   /* Parse the filename.  */
02462   if (*input_line_pointer == '"')
02463     {
02464       if ((filename = demand_copy_C_string (&len)) == NULL)
02465        return;
02466     }
02467   else
02468     {
02469       SKIP_WHITESPACE ();
02470       len = 0;
02471       while (!is_end_of_line[(int) *input_line_pointer]
02472             && !ISSPACE (*input_line_pointer))
02473        {
02474          obstack_1grow (&notes, *input_line_pointer);
02475          ++input_line_pointer;
02476          ++len;
02477        }
02478       obstack_1grow (&notes, '\0');
02479       filename = obstack_finish (&notes);
02480     }
02481   demand_empty_rest_of_line ();
02482 
02483   tic54x_set_default_include (0);
02484   path = xmalloc ((unsigned long) len + include_dir_maxlen + 5);
02485 
02486   for (i = 0; i < include_dir_count; i++)
02487     {
02488       FILE *try;
02489 
02490       strcpy (path, include_dirs[i]);
02491       strcat (path, "/");
02492       strcat (path, filename);
02493       if ((try = fopen (path, "r")) != NULL)
02494        {
02495          fclose (try);
02496          break;
02497        }
02498     }
02499 
02500   if (i >= include_dir_count)
02501     {
02502       free (path);
02503       path = filename;
02504     }
02505 
02506   /* FIXME: if path is found, malloc'd storage is not freed.  Of course, this
02507      happens all over the place, and since the assembler doesn't usually keep
02508      running for a very long time, it really doesn't matter.  */
02509   register_dependency (path);
02510 
02511   /* Expand all archive entries to temporary files and include them.  */
02512   abfd = bfd_openr (path, NULL);
02513   if (!abfd)
02514     {
02515       as_bad (_("can't open macro library file '%s' for reading: %s"),
02516              path, bfd_errmsg (bfd_get_error ()));
02517       ignore_rest_of_line ();
02518       return;
02519     }
02520   if (!bfd_check_format (abfd, bfd_archive))
02521     {
02522       as_bad (_("File '%s' not in macro archive format"), path);
02523       ignore_rest_of_line ();
02524       return;
02525     }
02526 
02527   /* Open each BFD as binary (it should be straight ASCII text).  */
02528   for (mbfd = bfd_openr_next_archived_file (abfd, NULL);
02529        mbfd != NULL; mbfd = bfd_openr_next_archived_file (abfd, mbfd))
02530     {
02531       /* Get a size at least as big as the archive member.  */
02532       bfd_size_type size = bfd_get_size (mbfd);
02533       char *buf = xmalloc (size);
02534       char *fname = tmpnam (NULL);
02535       FILE *ftmp;
02536 
02537       /* We're not sure how big it is, but it will be smaller than "size".  */
02538       bfd_bread (buf, size, mbfd);
02539 
02540       /* Write to a temporary file, then use s_include to include it
02541         a bit of a hack.  */
02542       ftmp = fopen (fname, "w+b");
02543       fwrite ((void *) buf, size, 1, ftmp);
02544       if (buf[size - 1] != '\n')
02545        fwrite ("\n", 1, 1, ftmp);
02546       fclose (ftmp);
02547       free (buf);
02548       input_scrub_insert_file (fname);
02549       unlink (fname);
02550     }
02551 }
02552 
02553 const pseudo_typeS md_pseudo_table[] =
02554 {
02555   { "algebraic", s_ignore                 ,          0 },
02556   { "align"    , tic54x_align_words       ,        128 },
02557   { "ascii"    , tic54x_stringer          ,        'p' },
02558   { "asciz"    , tic54x_stringer          ,        'P' },
02559   { "even"     , tic54x_align_words       ,          2 },
02560   { "asg"      , tic54x_asg               ,          0 },
02561   { "eval"     , tic54x_eval              ,          0 },
02562   { "bss"      , tic54x_bss               ,          0 },
02563   { "byte"     , tic54x_cons              ,        'b' },
02564   { "ubyte"    , tic54x_cons              ,        'B' },
02565   { "char"     , tic54x_cons              ,        'c' },
02566   { "uchar"    , tic54x_cons              ,        'C' },
02567   { "clink"    , tic54x_clink             ,          0 },
02568   { "c_mode"   , tic54x_address_mode      ,     c_mode },
02569   { "copy"     , tic54x_include           ,        'c' },
02570   { "include"  , tic54x_include           ,        'i' },
02571   { "data"     , tic54x_sect              ,        'd' },
02572   { "double"   , tic54x_float_cons        ,        'd' },
02573   { "ldouble"  , tic54x_float_cons        ,        'l' },
02574   { "drlist"   , s_ignore                 ,          0 },
02575   { "drnolist" , s_ignore                 ,          0 },
02576   { "emsg"     , tic54x_message           ,        'e' },
02577   { "mmsg"     , tic54x_message           ,        'm' },
02578   { "wmsg"     , tic54x_message           ,        'w' },
02579   { "far_mode" , tic54x_address_mode      ,   far_mode },
02580   { "fclist"   , tic54x_fclist            ,          1 },
02581   { "fcnolist" , tic54x_fclist            ,          0 },
02582   { "field"    , tic54x_field             ,         -1 },
02583   { "float"    , tic54x_float_cons        ,        'f' },
02584   { "xfloat"   , tic54x_float_cons        ,        'x' },
02585   { "global"   , tic54x_global            ,        'g' },
02586   { "def"      , tic54x_global            ,        'd' },
02587   { "ref"      , tic54x_global            ,        'r' },
02588   { "half"     , tic54x_cons              ,        'h' },
02589   { "uhalf"    , tic54x_cons              ,        'H' },
02590   { "short"    , tic54x_cons              ,        's' },
02591   { "ushort"   , tic54x_cons              ,        'S' },
02592   { "if"       , s_if                     , (int) O_ne },
02593   { "elseif"   , s_elseif                 , (int) O_ne },
02594   { "else"     , s_else                   ,          0 },
02595   { "endif"    , s_endif                  ,          0 },
02596   { "int"      , tic54x_cons              ,        'i' },
02597   { "uint"     , tic54x_cons              ,        'I' },
02598   { "word"     , tic54x_cons              ,        'w' },
02599   { "uword"    , tic54x_cons              ,        'W' },
02600   { "label"    , tic54x_label             ,          0 }, /* Loadtime
02601                                                              address.  */
02602   { "length"   , s_ignore                 ,          0 },
02603   { "width"    , s_ignore                 ,          0 },
02604   { "long"     , tic54x_cons              ,        'l' },
02605   { "ulong"    , tic54x_cons              ,        'L' },
02606   { "xlong"    , tic54x_cons              ,        'x' },
02607   { "loop"     , tic54x_loop              ,       1024 },
02608   { "break"    , tic54x_break             ,          0 },
02609   { "endloop"  , tic54x_endloop           ,          0 },
02610   { "mlib"     , tic54x_mlib              ,          0 },
02611   { "mlist"    , s_ignore                 ,          0 },
02612   { "mnolist"  , s_ignore                 ,          0 },
02613   { "mmregs"   , tic54x_mmregs            ,          0 },
02614   { "newblock" , tic54x_clear_local_labels,          0 },
02615   { "option"   , s_ignore                 ,          0 },
02616   { "p2align"  , tic54x_p2align           ,          0 },
02617   { "sblock"   , tic54x_sblock            ,          0 },
02618   { "sect"     , tic54x_sect              ,        '*' },
02619   { "set"      , tic54x_set               ,          0 },
02620   { "equ"      , tic54x_set               ,          0 },
02621   { "space"    , tic54x_space             ,          0 },
02622   { "bes"      , tic54x_space             ,          1 },
02623   { "sslist"   , tic54x_sslist            ,          1 },
02624   { "ssnolist" , tic54x_sslist            ,          0 },
02625   { "string"   , tic54x_stringer          ,        's' },
02626   { "pstring"  , tic54x_stringer          ,        'p' },
02627   { "struct"   , tic54x_struct            ,          0 },
02628   { "tag"      , tic54x_tag               ,          0 },
02629   { "endstruct", tic54x_endstruct         ,          0 },
02630   { "tab"      , s_ignore                 ,          0 },
02631   { "text"     , tic54x_sect              ,        't' },
02632   { "union"    , tic54x_struct            ,          1 },
02633   { "endunion" , tic54x_endstruct         ,          1 },
02634   { "usect"    , tic54x_usect             ,          0 },
02635   { "var"      , tic54x_var               ,          0 },
02636   { "version"  , tic54x_version           ,          0 },
02637   {0           , 0                        ,          0 }
02638 };
02639 
02640 int
02641 md_parse_option (c, arg)
02642      int c;
02643      char *arg;
02644 {
02645   switch (c)
02646     {
02647     default:
02648       return 0;
02649     case OPTION_COFF_VERSION:
02650       {
02651        int version = atoi (arg);
02652 
02653        if (version != 0 && version != 1 && version != 2)
02654          as_fatal (_("Bad COFF version '%s'"), arg);
02655        /* FIXME -- not yet implemented.  */
02656        break;
02657       }
02658     case OPTION_CPU_VERSION:
02659       {
02660        cpu = lookup_version (arg);
02661        cpu_needs_set = 1;
02662        if (cpu == VNONE)
02663          as_fatal (_("Bad CPU version '%s'"), arg);
02664        break;
02665       }
02666     case OPTION_ADDRESS_MODE:
02667       amode = far_mode;
02668       address_mode_needs_set = 1;
02669       break;
02670     case OPTION_STDERR_TO_FILE:
02671       {
02672        char *filename = arg;
02673        FILE *fp = fopen (filename, "w+");
02674 
02675        if (fp == NULL)
02676          as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
02677        fclose (fp);
02678        if ((fp = freopen (filename, "w+", stderr)) == NULL)
02679          as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
02680        break;
02681       }
02682     }
02683 
02684   return 1;
02685 }
02686 
02687 /* Create a "local" substitution string hash table for a new macro level
02688    Some docs imply that macros have to use .newblock in order to be able
02689    to re-use a local label.  We effectively do an automatic .newblock by
02690    deleting the local label hash between macro invocations.  */
02691 
02692 void
02693 tic54x_macro_start ()
02694 {
02695   ++macro_level;
02696   subsym_hash[macro_level] = hash_new ();
02697   local_label_hash[macro_level] = hash_new ();
02698 }
02699 
02700 void
02701 tic54x_macro_info (macro)
02702      const macro_entry *macro;
02703 {
02704   const formal_entry *entry;
02705 
02706   /* Put the formal args into the substitution symbol table.  */
02707   for (entry = macro->formals; entry; entry = entry->next)
02708     {
02709       char *name = strncpy (xmalloc (entry->name.len + 1),
02710                          entry->name.ptr, entry->name.len);
02711       char *value = strncpy (xmalloc (entry->actual.len + 1),
02712                           entry->actual.ptr, entry->actual.len);
02713 
02714       name[entry->name.len] = '\0';
02715       value[entry->actual.len] = '\0';
02716       hash_insert (subsym_hash[macro_level], name, value);
02717     }
02718 }
02719 
02720 /* Get rid of this macro's .var's, arguments, and local labels.  */
02721 
02722 void
02723 tic54x_macro_end ()
02724 {
02725   hash_die (subsym_hash[macro_level]);
02726   subsym_hash[macro_level] = NULL;
02727   hash_die (local_label_hash[macro_level]);
02728   local_label_hash[macro_level] = NULL;
02729   --macro_level;
02730 }
02731 
02732 static int
02733 subsym_symlen (a, ignore)
02734      char *a;
02735      char *ignore ATTRIBUTE_UNUSED;
02736 {
02737   return strlen (a);
02738 }
02739 
02740 /* Compare symbol A to string B.  */
02741 
02742 static int
02743 subsym_symcmp (a, b)
02744      char *a;
02745      char *b;
02746 {
02747   return strcmp (a, b);
02748 }
02749 
02750 /* Return the index of the first occurrence of B in A, or zero if none
02751    assumes b is an integer char value as a string.  Index is one-based.  */
02752 
02753 static int
02754 subsym_firstch (a, b)
02755      char *a;
02756      char *b;
02757 {
02758   int val = atoi (b);
02759   char *tmp = strchr (a, val);
02760 
02761   return tmp ? tmp - a + 1 : 0;
02762 }
02763 
02764 /* Similar to firstch, but returns index of last occurrence of B in A.  */
02765 
02766 static int
02767 subsym_lastch (a, b)
02768      char *a;
02769      char *b;
02770 {
02771   int val = atoi (b);
02772   char *tmp = strrchr (a, val);
02773 
02774   return tmp ? tmp - a + 1 : 0;
02775 }
02776 
02777 /* Returns 1 if string A is defined in the symbol table (NOT the substitution
02778    symbol table).  */
02779 
02780 static int
02781 subsym_isdefed (a, ignore)
02782      char *a;
02783      char *ignore ATTRIBUTE_UNUSED;
02784 {
02785   symbolS *symbolP = symbol_find (a);
02786 
02787   return symbolP != NULL;
02788 }
02789 
02790 /* Assign first member of comma-separated list B (e.g. "1,2,3") to the symbol
02791    A, or zero if B is a null string.  Both arguments *must* be substitution
02792    symbols, unsubstituted.  */
02793 
02794 static int
02795 subsym_ismember (sym, list)
02796      char *sym;
02797      char *list;
02798 {
02799   char *elem, *ptr, *listv;
02800 
02801   if (!list)
02802     return 0;
02803 
02804   listv = subsym_lookup (list, macro_level);
02805   if (!listv)
02806     {
02807       as_bad (_("Undefined substitution symbol '%s'"), list);
02808       ignore_rest_of_line ();
02809       return 0;
02810     }
02811 
02812   ptr = elem = xmalloc (strlen (listv) + 1);
02813   strcpy (elem, listv);
02814   while (*ptr && *ptr != ',')
02815     ++ptr;
02816   *ptr++ = 0;
02817 
02818   subsym_create_or_replace (sym, elem);
02819 
02820   /* Reassign the list.  */
02821   subsym_create_or_replace (list, ptr);
02822 
02823   /* Assume this value, docs aren't clear.  */
02824   return *list != 0;
02825 }
02826 
02827 /* Return zero if not a constant; otherwise:
02828    1 if binary
02829    2 if octal
02830    3 if hexadecimal
02831    4 if character
02832    5 if decimal.  */
02833 
02834 static int
02835 subsym_iscons (a, ignore)
02836      char *a;
02837      char *ignore ATTRIBUTE_UNUSED;
02838 {
02839   expressionS exp;
02840 
02841   parse_expression (a, &exp);
02842 
02843   if (exp.X_op == O_constant)
02844     {
02845       int len = strlen (a);
02846 
02847       switch (TOUPPER (a[len - 1]))
02848        {
02849        case 'B':
02850          return 1;
02851        case 'Q':
02852          return 2;
02853        case 'H':
02854          return 3;
02855        case '\'':
02856          return 4;
02857        default:
02858          break;
02859        }
02860       /* No suffix; either octal, hex, or decimal.  */
02861       if (*a == '0' && len > 1)
02862        {
02863          if (TOUPPER (a[1]) == 'X')
02864            return 3;
02865          return 2;
02866        }
02867       return 5;
02868     }
02869 
02870   return 0;
02871 }
02872 
02873 /* Return 1 if A is a valid symbol name.  Expects string input.   */
02874 
02875 static int
02876 subsym_isname (a, ignore)
02877      char *a;
02878      char *ignore ATTRIBUTE_UNUSED;
02879 {
02880   if (!is_name_beginner (*a))
02881     return 0;
02882   while (*a)
02883     {
02884       if (!is_part_of_name (*a))
02885        return 0;
02886       ++a;
02887     }
02888   return 1;
02889 }
02890 
02891 /* Return whether the string is a register; accepts ar0-7, unless .mmregs has
02892    been seen; if so, recognize any memory-mapped register.
02893    Note this does not recognize "A" or "B" accumulators.  */
02894 
02895 static int
02896 subsym_isreg (a, ignore)
02897      char *a;
02898      char *ignore ATTRIBUTE_UNUSED;
02899 {
02900   if (hash_find (reg_hash, a))
02901     return 1;
02902   if (hash_find (mmreg_hash, a))
02903     return 1;
02904   return 0;
02905 }
02906 
02907 /* Return the structure size, given the stag.  */
02908 
02909 static int
02910 subsym_structsz (name, ignore)
02911      char *name;
02912      char *ignore ATTRIBUTE_UNUSED;
02913 {
02914   struct stag *stag = (struct stag *) hash_find (stag_hash, name);
02915 
02916   if (stag)
02917     return stag->size;
02918 
02919   return 0;
02920 }
02921 
02922 /* If anybody actually uses this, they can fix it :)
02923    FIXME I'm not sure what the "reference point" of a structure is.  It might
02924    be either the initial offset given .struct, or it may be the offset of the
02925    structure within another structure, or it might be something else
02926    altogether.  since the TI assembler doesn't seem to ever do anything but
02927    return zero, we punt and return zero.  */
02928 
02929 static int
02930 subsym_structacc (stag_name, ignore)
02931      char *stag_name ATTRIBUTE_UNUSED;
02932      char *ignore ATTRIBUTE_UNUSED;
02933 {
02934   return 0;
02935 }
02936 
02937 static float
02938 math_ceil (arg1, ignore)
02939      float arg1;
02940      float ignore ATTRIBUTE_UNUSED;
02941 {
02942   return (float) ceil (arg1);
02943 }
02944 
02945 static float
02946 math_cvi (arg1, ignore)
02947      float arg1;
02948      float ignore ATTRIBUTE_UNUSED;
02949 {
02950   return (int) arg1;
02951 }
02952 
02953 static float
02954 math_floor (arg1, ignore)
02955      float arg1;
02956      float ignore ATTRIBUTE_UNUSED;
02957 {
02958   return (float) floor (arg1);
02959 }
02960 
02961 static float
02962 math_fmod (arg1, arg2)
02963      float arg1;
02964      float arg2;
02965 {
02966   return (int) arg1 % (int) arg2;
02967 }
02968 
02969 static float
02970 math_int (arg1, ignore)
02971      float arg1;
02972      float ignore ATTRIBUTE_UNUSED;
02973 {
02974   return ((float) ((int) arg1)) == arg1;
02975 }
02976 
02977 static float
02978 math_round (arg1, ignore)
02979      float arg1;
02980      float ignore ATTRIBUTE_UNUSED;
02981 {
02982   return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5);
02983 }
02984 
02985 static float
02986 math_sgn (arg1, ignore)
02987      float arg1;
02988      float ignore ATTRIBUTE_UNUSED;
02989 {
02990   return (arg1 < 0) ? -1 : (arg1 ? 1 : 0);
02991 }
02992 
02993 static float
02994 math_trunc (arg1, ignore)
02995      float arg1;
02996      float ignore ATTRIBUTE_UNUSED;
02997 {
02998   return (int) arg1;
02999 }
03000 
03001 static float
03002 math_acos (arg1, ignore)
03003      float arg1;
03004      float ignore ATTRIBUTE_UNUSED;
03005 {
03006   return (float) acos (arg1);
03007 }
03008 
03009 static float
03010 math_asin (arg1, ignore)
03011      float arg1;
03012      float ignore ATTRIBUTE_UNUSED;
03013 {
03014   return (float) asin (arg1);
03015 }
03016 
03017 static float
03018 math_atan (arg1, ignore)
03019      float arg1;
03020      float ignore ATTRIBUTE_UNUSED;
03021 {
03022   return (float) atan (arg1);
03023 }
03024 
03025 static float
03026 math_atan2 (arg1, arg2)
03027      float arg1;
03028      float arg2;
03029 {
03030   return (float) atan2 (arg1, arg2);
03031 }
03032 
03033 static float
03034 math_cosh (arg1, ignore)
03035      float arg1;
03036      float ignore ATTRIBUTE_UNUSED;
03037 {
03038   return (float) cosh (arg1);
03039 }
03040 
03041 static float
03042 math_cos (arg1, ignore)
03043      float arg1;
03044      float ignore ATTRIBUTE_UNUSED;
03045 {
03046   return (float) cos (arg1);
03047 }
03048 
03049 static float
03050 math_cvf (arg1, ignore)
03051      float arg1;
03052      float ignore ATTRIBUTE_UNUSED;
03053 {
03054   return (float) arg1;
03055 }
03056 
03057 static float
03058 math_exp (arg1, ignore)
03059      float arg1;
03060      float ignore ATTRIBUTE_UNUSED;
03061 {
03062   return (float) exp (arg1);
03063 }
03064 
03065 static float
03066 math_fabs (arg1, ignore)
03067      float arg1;
03068      float ignore ATTRIBUTE_UNUSED;
03069 {
03070   return (float) fabs (arg1);
03071 }
03072 
03073 /* expr1 * 2^expr2.  */
03074 
03075 static float
03076 math_ldexp (arg1, arg2)
03077      float arg1;
03078      float arg2;
03079 {
03080   return arg1 * (float) pow (2.0, arg2);
03081 }
03082 
03083 static float
03084 math_log10 (arg1, ignore)
03085      float arg1;
03086      float ignore ATTRIBUTE_UNUSED;
03087 {
03088   return (float) log10 (arg1);
03089 }
03090 
03091 static float
03092 math_log (arg1, ignore)
03093      float arg1;
03094      float ignore ATTRIBUTE_UNUSED;
03095 {
03096   return (float) log (arg1);
03097 }
03098 
03099 static float
03100 math_max (arg1, arg2)
03101      float arg1;
03102      float arg2;
03103 {
03104   return (arg1 > arg2) ? arg1 : arg2;
03105 }
03106 
03107 static float
03108 math_min (arg1, arg2)
03109      float arg1;
03110      float arg2;
03111 {
03112   return (arg1 < arg2) ? arg1 : arg2;
03113 }
03114 
03115 static float
03116 math_pow (arg1, arg2)
03117      float arg1;
03118      float arg2;
03119 {
03120   return (float) pow (arg1, arg2);
03121 }
03122 
03123 static float
03124 math_sin (arg1, ignore)
03125      float arg1;
03126      float ignore ATTRIBUTE_UNUSED;
03127 {
03128   return (float) sin (arg1);
03129 }
03130 
03131 static float
03132 math_sinh (arg1, ignore)
03133      float arg1;
03134      float ignore ATTRIBUTE_UNUSED;
03135 {
03136   return (float) sinh (arg1);
03137 }
03138 
03139 static float
03140 math_sqrt (arg1, ignore)
03141      float arg1;
03142      float ignore ATTRIBUTE_UNUSED;
03143 {
03144   return (float) sqrt (arg1);
03145 }
03146 
03147 static float
03148 math_tan (arg1, ignore)
03149      float arg1;
03150      float ignore ATTRIBUTE_UNUSED;
03151 {
03152   return (float) tan (arg1);
03153 }
03154 
03155 static float
03156 math_tanh (arg1, ignore)
03157      float arg1;
03158      float ignore ATTRIBUTE_UNUSED;
03159 {
03160   return (float) tanh (arg1);
03161 }
03162 
03163 /* Built-in substitution symbol functions and math functions.  */
03164 typedef struct
03165 {
03166   char *name;
03167   int (*proc) PARAMS ((char *, char *));
03168   int nargs;
03169 } subsym_proc_entry;
03170 
03171 static const subsym_proc_entry subsym_procs[] =
03172 {
03173   /* Assembler built-in string substitution functions.  */
03174   { "$symlen", subsym_symlen, 1,  },
03175   { "$symcmp", subsym_symcmp, 2,  },
03176   { "$firstch", subsym_firstch, 2,  },
03177   { "$lastch", subsym_lastch, 2,  },
03178   { "$isdefed", subsym_isdefed, 1,  },
03179   { "$ismember", subsym_ismember, 2,  },
03180   { "$iscons", subsym_iscons, 1,  },
03181   { "$isname", subsym_isname, 1,  },
03182   { "$isreg", subsym_isreg, 1,  },
03183   { "$structsz", subsym_structsz, 1,  },
03184   { "$structacc", subsym_structacc, 1,  },
03185   { NULL, NULL, 0 },
03186 };
03187 
03188 typedef struct
03189 {
03190   char *name;
03191   float (*proc) PARAMS ((float, float));
03192   int nargs;
03193   int int_return;
03194 } math_proc_entry;
03195 
03196 static const math_proc_entry math_procs[] =
03197 {
03198   /* Integer-returning built-in math functions.  */
03199   { "$cvi", math_cvi, 1, 1 },
03200   { "$int", math_int, 1, 1 },
03201   { "$sgn", math_sgn, 1, 1 },
03202 
03203   /* Float-returning built-in math functions.  */
03204   { "$acos", math_acos, 1, 0 },
03205   { "$asin", math_asin, 1, 0 },
03206   { "$atan", math_atan, 1, 0 },
03207   { "$atan2", math_atan2, 2, 0 },
03208   { "$ceil", math_ceil, 1, 0 },
03209   { "$cosh", math_cosh, 1, 0 },
03210   { "$cos", math_cos, 1, 0 },
03211   { "$cvf", math_cvf, 1, 0 },
03212   { "$exp", math_exp, 1, 0 },
03213   { "$fabs", math_fabs, 1, 0 },
03214   { "$floor", math_floor, 1, 0 },
03215   { "$fmod", math_fmod, 2, 0 },
03216   { "$ldexp", math_ldexp, 2, 0 },
03217   { "$log10", math_log10, 1, 0 },
03218   { "$log", math_log, 1, 0 },
03219   { "$max", math_max, 2, 0 },
03220   { "$min", math_min, 2, 0 },
03221   { "$pow", math_pow, 2, 0 },
03222   { "$round", math_round, 1, 0 },
03223   { "$sin", math_sin, 1, 0 },
03224   { "$sinh", math_sinh, 1, 0 },
03225   { "$sqrt", math_sqrt, 1, 0 },
03226   { "$tan", math_tan, 1, 0 },
03227   { "$tanh", math_tanh, 1, 0 },
03228   { "$trunc", math_trunc, 1, 0 },
03229   { NULL, NULL, 0, 0 },
03230 };
03231 
03232 void
03233 md_begin ()
03234 {
03235   template *tm;
03236   symbol *sym;
03237   const subsym_proc_entry *subsym_proc;
03238   const math_proc_entry *math_proc;
03239   const char *hash_err;
03240   char **symname;
03241   char *TIC54X_DIR = getenv ("TIC54X_DIR");
03242   char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
03243 
03244   local_label_id = 0;
03245 
03246   /* Look for A_DIR and add it to the include list.  */
03247   if (A_DIR != NULL)
03248     {
03249       char *tmp = xstrdup (A_DIR);
03250 
03251       do
03252        {
03253          char *next = strchr (tmp, ';');
03254 
03255          if (next)
03256            *next++ = '\0';
03257          add_include_dir (tmp);
03258          tmp = next;
03259        }
03260       while (tmp != NULL);
03261     }
03262 
03263   op_hash = hash_new ();
03264   for (tm = (template *) tic54x_optab; tm->name; tm++)
03265     {
03266       if (hash_find (op_hash, tm->name))
03267        continue;
03268       hash_err = hash_insert (op_hash, tm->name, (char *) tm);
03269       if (hash_err)
03270        as_fatal ("Internal Error: Can't hash %s: %s",
03271                 tm->name, hash_err);
03272     }
03273   parop_hash = hash_new ();
03274   for (tm = (template *) tic54x_paroptab; tm->name; tm++)
03275     {
03276       if (hash_find (parop_hash, tm->name))
03277        continue;
03278       hash_err = hash_insert (parop_hash, tm->name, (char *) tm);
03279       if (hash_err)
03280        as_fatal ("Internal Error: Can't hash %s: %s",
03281                 tm->name, hash_err);
03282     }
03283   reg_hash = hash_new ();
03284   for (sym = (symbol *) regs; sym->name; sym++)
03285     {
03286       /* Add basic registers to the symbol table.  */
03287       symbolS *symbolP = symbol_new (sym->name, absolute_section,
03288                                  (valueT) sym->value, &zero_address_frag);
03289       SF_SET_LOCAL (symbolP);
03290       symbol_table_insert (symbolP);
03291       hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
03292     }
03293   for (sym = (symbol *) mmregs; sym->name; sym++)
03294     hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
03295   mmreg_hash = hash_new ();
03296   for (sym = (symbol *) mmregs; sym->name; sym++)
03297     hash_err = hash_insert (mmreg_hash, sym->name, (char *) sym);
03298 
03299   cc_hash = hash_new ();
03300   for (sym = (symbol *) condition_codes; sym->name; sym++)
03301     hash_err = hash_insert (cc_hash, sym->name, (char *) sym);
03302 
03303   cc2_hash = hash_new ();
03304   for (sym = (symbol *) cc2_codes; sym->name; sym++)
03305     hash_err = hash_insert (cc2_hash, sym->name, (char *) sym);
03306 
03307   cc3_hash = hash_new ();
03308   for (sym = (symbol *) cc3_codes; sym->name; sym++)
03309     hash_err = hash_insert (cc3_hash, sym->name, (char *) sym);
03310 
03311   sbit_hash = hash_new ();
03312   for (sym = (symbol *) status_bits; sym->name; sym++)
03313     hash_err = hash_insert (sbit_hash, sym->name, (char *) sym);
03314 
03315   misc_symbol_hash = hash_new ();
03316   for (symname = (char **) misc_symbols; *symname; symname++)
03317     hash_err = hash_insert (misc_symbol_hash, *symname, *symname);
03318 
03319   /* Only the base substitution table and local label table are initialized;
03320      the others (for local macro substitution) get instantiated as needed.  */
03321   local_label_hash[0] = hash_new ();
03322   subsym_hash[0] = hash_new ();
03323   for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++)
03324     hash_err = hash_insert (subsym_hash[0], subsym_proc->name,
03325                          (char *) subsym_proc);
03326 
03327   math_hash = hash_new ();
03328   for (math_proc = math_procs; math_proc->name; math_proc++)
03329     {
03330       /* Insert into the main subsym hash for recognition; insert into
03331         the math hash to actually store information.  */
03332       hash_err = hash_insert (subsym_hash[0], math_proc->name,
03333                            (char *) math_proc);
03334       hash_err = hash_insert (math_hash, math_proc->name,
03335                            (char *) math_proc);
03336     }
03337   subsym_recurse_hash = hash_new ();
03338   stag_hash = hash_new ();
03339 }
03340 
03341 static int
03342 is_accumulator (operand)
03343      struct opstruct *operand;
03344 {
03345   return strcasecmp (operand->buf, "a") == 0
03346     || strcasecmp (operand->buf, "b") == 0;
03347 }
03348 
03349 /* Return the number of operands found, or -1 on error, copying the
03350    operands into the given array and the accompanying expressions into
03351    the next array.  */
03352 
03353 static int
03354 get_operands (operands, line)
03355      struct opstruct operands[];
03356      char *line;
03357 {
03358   char *lptr = line;
03359   int numexp = 0;
03360   int expecting_operand = 0;
03361   int i;
03362 
03363   while (numexp < MAX_OPERANDS && !is_end_of_line[(int) *lptr])
03364     {
03365       int paren_not_balanced = 0;
03366       char *op_start, *op_end;
03367 
03368       while (*lptr && ISSPACE (*lptr))
03369        ++lptr;
03370       op_start = lptr;
03371       while (paren_not_balanced || *lptr != ',')
03372        {
03373          if (*lptr == '\0')
03374            {
03375              if (paren_not_balanced)
03376               {
03377                 as_bad ("Unbalanced parenthesis in operand %d", numexp);
03378                 return -1;
03379               }
03380              else
03381               break;
03382            }
03383          if (*lptr == '(')
03384            ++paren_not_balanced;
03385          else if (*lptr == ')')
03386            --paren_not_balanced;
03387          ++lptr;
03388        }
03389       op_end = lptr;
03390       if (op_end != op_start)
03391        {
03392          int len = op_end - op_start;
03393 
03394          strncpy (operands[numexp].buf, op_start, len);
03395          operands[numexp].buf[len] = 0;
03396          /* Trim trailing spaces; while the preprocessor gets rid of most,
03397             there are weird usage patterns that can introduce them
03398             (i.e. using strings for macro args).  */
03399          while (len > 0 && ISSPACE (operands[numexp].buf[len - 1]))
03400            operands[numexp].buf[--len] = 0;
03401          lptr = op_end;
03402          ++numexp;
03403        }
03404       else
03405        {
03406          if (expecting_operand || *lptr == ',')
03407            {
03408              as_bad ("Expecting operand after ','");
03409              return -1;
03410            }
03411        }
03412       if (*lptr == ',')
03413        {
03414          if (*++lptr == '\0')
03415            {
03416              as_bad ("Expecting operand after ','");
03417              return -1;
03418            }
03419          expecting_operand = 1;
03420        }
03421     }
03422 
03423   while (*lptr && ISSPACE (*lptr++))
03424     ;
03425   if (!is_end_of_line[(int) *lptr])
03426     {
03427       as_bad ("Extra junk on line");
03428       return -1;
03429     }
03430 
03431   /* OK, now parse them into expressions.  */
03432   for (i = 0; i < numexp; i++)
03433     {
03434       memset (&operands[i].exp, 0, sizeof (operands[i].exp));
03435       if (operands[i].buf[0] == '#')
03436        {
03437          /* Immediate.  */
03438          parse_expression (operands[i].buf + 1, &operands[i].exp);
03439        }
03440       else if (operands[i].buf[0] == '@')
03441        {
03442          /* Direct notation.  */
03443          parse_expression (operands[i].buf + 1, &operands[i].exp);
03444        }
03445       else if (operands[i].buf[0] == '*')
03446        {
03447          /* Indirect.  */
03448          char *paren = strchr (operands[i].buf, '(');
03449 
03450          /* Allow immediate syntax in the inner expression.  */
03451          if (paren && paren[1] == '#')
03452            *++paren = '(';
03453 
03454          /* Pull out the lk expression or SP offset, if present.  */
03455          if (paren != NULL)
03456            {
03457              int len = strlen (paren);
03458              char *end = paren + len;
03459              int c;
03460 
03461              while (end[-1] != ')')
03462               if (--end <= paren)
03463                 {
03464                   as_bad (_("Badly formed address expression"));
03465                   return -1;
03466                 }
03467              c = *end;
03468              *end = '\0';
03469              parse_expression (paren, &operands[i].exp);
03470              *end = c;
03471            }
03472          else
03473            operands[i].exp.X_op = O_absent;
03474        }
03475       else
03476        parse_expression (operands[i].buf, &operands[i].exp);
03477     }
03478 
03479   return numexp;
03480 }
03481 
03482 /* Predicates for different operand types.  */
03483 
03484 static int
03485 is_immediate (operand)
03486      struct opstruct *operand;
03487 {
03488   return *operand->buf == '#';
03489 }
03490 
03491 /* This is distinguished from immediate because some numbers must be constants
03492    and must *not* have the '#' prefix.  */
03493 
03494 static int
03495 is_absolute (operand)
03496      struct opstruct *operand;
03497 {
03498   return operand->exp.X_op == O_constant && !is_immediate (operand);
03499 }
03500 
03501 /* Is this an indirect operand?  */
03502 
03503 static int
03504 is_indirect (operand)
03505      struct opstruct *operand;
03506 {
03507   return operand->buf[0] == '*';
03508 }
03509 
03510 /* Is this a valid dual-memory operand?  */
03511 
03512 static int
03513 is_dual (operand)
03514      struct opstruct *operand;
03515 {
03516   if (is_indirect (operand) && strncasecmp (operand->buf, "*ar", 3) == 0)
03517     {
03518       char *tmp = operand->buf + 3;
03519       int arf;
03520       int valid_mod;
03521 
03522       arf = *tmp++ - '0';
03523       /* Only allow *ARx, *ARx-, *ARx+, or *ARx+0%.  */
03524       valid_mod = *tmp == '\0' ||
03525        strcasecmp (tmp, "-") == 0 ||
03526        strcasecmp (tmp, "+") == 0 ||
03527        strcasecmp (tmp, "+0%") == 0;
03528       return arf >= 2 && arf <= 5 && valid_mod;
03529     }
03530   return 0;
03531 }
03532 
03533 static int
03534 is_mmreg (operand)
03535      struct opstruct *operand;
03536 {
03537   return (is_absolute (operand)
03538          || is_immediate (operand)
03539          || hash_find (mmreg_hash, operand->buf) != 0);
03540 }
03541 
03542 static int
03543 is_type (operand, type)
03544      struct opstruct *operand;
03545      enum optype type;
03546 {
03547   switch (type)
03548     {
03549     case OP_None:
03550       return operand->buf[0] == 0;
03551     case OP_Xmem:
03552     case OP_Ymem:
03553       return is_dual (operand);
03554     case OP_Sind:
03555       return is_indirect (operand);
03556     case OP_xpmad_ms7:
03557       /* This one *must* be immediate.  */
03558       return is_immediate (operand);
03559     case OP_xpmad:
03560     case OP_pmad:
03561     case OP_PA:
03562     case OP_dmad:
03563     case OP_Lmem:
03564     case OP_MMR:
03565       return 1;
03566     case OP_Smem:
03567       /* Address may be a numeric, indirect, or an expression.  */
03568       return !is_immediate (operand);
03569     case OP_MMRY:
03570     case OP_MMRX:
03571       return is_mmreg (operand);
03572     case OP_SRC:
03573     case OP_SRC1:
03574     case OP_RND:
03575     case OP_DST:
03576       return is_accumulator (operand);
03577     case OP_B:
03578       return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'B';
03579     case OP_A:
03580       return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'A';
03581     case OP_ARX:
03582       return strncasecmp ("ar", operand->buf, 2) == 0
03583        && ISDIGIT (operand->buf[2]);
03584     case OP_SBIT:
03585       return hash_find (sbit_hash, operand->buf) != 0 || is_absolute (operand);
03586     case OP_CC:
03587       return hash_find (cc_hash, operand->buf) != 0;
03588     case OP_CC2:
03589       return hash_find (cc2_hash, operand->buf) != 0;
03590     case OP_CC3:
03591       return hash_find (cc3_hash, operand->buf) != 0
03592        || is_immediate (operand) || is_absolute (operand);
03593     case OP_16:
03594       return (is_immediate (operand) || is_absolute (operand))
03595        && operand->exp.X_add_number == 16;
03596     case OP_N:
03597       /* Allow st0 or st1 instead of a numeric.  */
03598       return is_absolute (operand) || is_immediate (operand) ||
03599        strcasecmp ("st0", operand->buf) == 0 ||
03600        strcasecmp ("st1", operand->buf) == 0;
03601     case OP_12:
03602     case OP_123:
03603       return is_absolute (operand) || is_immediate (operand);
03604     case OP_SHFT:
03605       return (is_immediate (operand) || is_absolute (operand))
03606        && operand->exp.X_add_number >= 0 && operand->exp.X_add_number < 16;
03607     case OP_SHIFT:
03608       /* Let this one catch out-of-range values.  */
03609       return (is_immediate (operand) || is_absolute (operand))
03610        && operand->exp.X_add_number != 16;
03611     case OP_BITC:
03612     case OP_031:
03613     case OP_k8:
03614       return is_absolute (operand) || is_immediate (operand);
03615     case OP_k8u:
03616       return is_immediate (operand)
03617        && operand->exp.X_op == O_constant
03618        && operand->exp.X_add_number >= 0
03619        && operand->exp.X_add_number < 256;
03620     case OP_lk:
03621     case OP_lku:
03622       /* Allow anything; assumes opcodes are ordered with Smem operands
03623         versions first.  */
03624       return 1;
03625     case OP_k5:
03626     case OP_k3:
03627     case OP_k9:
03628       /* Just make sure it's an integer; check range later.  */
03629       return is_immediate (operand);
03630     case OP_T:
03631       return strcasecmp ("t", operand->buf) == 0 ||
03632        strcasecmp ("treg", operand->buf) == 0;
03633     case OP_TS:
03634       return strcasecmp ("ts", operand->buf) == 0;
03635     case OP_ASM:
03636       return strcasecmp ("asm", operand->buf) == 0;
03637     case OP_TRN:
03638       return strcasecmp ("trn", operand->buf) == 0;
03639     case OP_DP:
03640       return strcasecmp ("dp", operand->buf) == 0;
03641     case OP_ARP:
03642       return strcasecmp ("arp", operand->buf) == 0;
03643     default:
03644       return 0;
03645     }
03646 }
03647 
03648 static int
03649 operands_match (insn, operands, opcount, refoptype, minops, maxops)
03650      tic54x_insn *insn;
03651      struct opstruct *operands;
03652      int opcount;
03653      const enum optype *refoptype;
03654      int minops;
03655      int maxops;
03656 {
03657   int op = 0, refop = 0;
03658 
03659   if (opcount == 0 && minops == 0)
03660     return 1;
03661 
03662   while (op <= maxops && refop <= maxops)
03663     {
03664       while (!is_type (&operands[op], OPTYPE (refoptype[refop])))
03665        {
03666          /* Skip an optional template operand if it doesn't agree
03667             with the current operand.  */
03668          if (refoptype[refop] & OPT)
03669            {
03670              ++refop;
03671              --maxops;
03672              if (refop > maxops)
03673               return 0;
03674            }
03675          else
03676            return 0;
03677        }
03678 
03679       /* Save the actual operand type for later use.  */
03680       operands[op].type = OPTYPE (refoptype[refop]);
03681       ++refop;
03682       ++op;
03683       /* Have we matched them all yet?  */
03684       if (op == opcount)
03685        {
03686          while (op < maxops)
03687            {
03688              /* If a later operand is *not* optional, no match.  */
03689              if ((refoptype[refop] & OPT) == 0)
03690               return 0;
03691              /* Flag any implicit default OP_DST operands so we know to add
03692                them explicitly when encoding the operand later.  */
03693              if (OPTYPE (refoptype[refop]) == OP_DST)
03694               insn->using_default_dst = 1;
03695              ++refop;
03696              ++op;
03697            }
03698 
03699          return 1;
03700        }
03701     }
03702 
03703   return 0;
03704 }
03705 
03706 /* 16-bit direct memory address
03707    Explicit dmad operands are always in last word of insn (usually second
03708    word, but bumped to third if lk addressing is used)
03709 
03710    We allow *(dmad) notation because the TI assembler allows it.
03711 
03712    XPC_CODE:
03713    0 for 16-bit addresses
03714    1 for full 23-bit addresses
03715    2 for the upper 7 bits of a 23-bit address (LDX).  */
03716 
03717 static int
03718 encode_dmad (insn, operand, xpc_code)
03719      tic54x_insn *insn;
03720      struct opstruct *operand;
03721      int xpc_code;
03722 {
03723   int op = 1 + insn->is_lkaddr;
03724 
03725   /* Only allow *(dmad) expressions; all others are invalid.  */
03726   if (is_indirect (operand) && operand->buf[strlen (operand->buf) - 1] != ')')
03727     {
03728       as_bad (_("Invalid dmad syntax '%s'"), operand->buf);
03729       return 0;
03730     }
03731 
03732   insn->opcode[op].addr_expr = operand->exp;
03733 
03734   if (insn->opcode[op].addr_expr.X_op == O_constant)
03735     {
03736       valueT value = insn->opcode[op].addr_expr.X_add_number;
03737 
03738       if (xpc_code == 1)
03739        {
03740          insn->opcode[0].word &= 0xFF80;
03741          insn->opcode[0].word |= (value >> 16) & 0x7F;
03742          insn->opcode[1].word = value & 0xFFFF;
03743        }
03744       else if (xpc_code == 2)
03745        insn->opcode[op].word = (value >> 16) & 0xFFFF;
03746       else
03747        insn->opcode[op].word = value;
03748     }
03749   else
03750     {
03751       /* Do the fixup later; just store the expression.  */
03752       insn->opcode[op].word = 0;
03753       insn->opcode[op].r_nchars = 2;
03754 
03755       if (amode == c_mode)
03756        insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
03757       else if (xpc_code == 1)
03758        {
03759          /* This relocation spans two words, so adjust accordingly.  */
03760          insn->opcode[0].addr_expr = operand->exp;
03761          insn->opcode[0].r_type = BFD_RELOC_TIC54X_23;
03762          insn->opcode[0].r_nchars = 4;
03763          insn->opcode[0].unresolved = 1;
03764          /* It's really 2 words, but we want to stop encoding after the
03765             first, since we must encode both words at once.  */
03766          insn->words = 1;
03767        }
03768       else if (xpc_code == 2)
03769        insn->opcode[op].r_type = BFD_RELOC_TIC54X_MS7_OF_23;
03770       else
03771        insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
03772 
03773       insn->opcode[op].unresolved = 1;
03774     }
03775 
03776   return 1;
03777 }
03778 
03779 /* 7-bit direct address encoding.  */
03780 
03781 static int
03782 encode_address (insn, operand)
03783      tic54x_insn *insn;
03784      struct opstruct *operand;
03785 {
03786   /* Assumes that dma addresses are *always* in word 0 of the opcode.  */
03787   insn->opcode[0].addr_expr = operand->exp;
03788 
03789   if (operand->exp.X_op == O_constant)
03790     insn->opcode[0].word |= (operand->exp.X_add_number & 0x7F);
03791   else
03792     {
03793       if (operand->exp.X_op == O_register)
03794         as_bad (_("Use the .mmregs directive to use memory-mapped register names such as '%s'"), operand->buf);
03795       /* Do the fixup later; just store the expression.  */
03796       insn->opcode[0].r_nchars = 1;
03797       insn->opcode[0].r_type = BFD_RELOC_TIC54X_PARTLS7;
03798       insn->opcode[0].unresolved = 1;
03799     }
03800 
03801   return 1;
03802 }
03803 
03804 static int
03805 encode_indirect (insn, operand)
03806      tic54x_insn *insn;
03807      struct opstruct *operand;
03808 {
03809   int arf;
03810   int mod;
03811 
03812   if (insn->is_lkaddr)
03813     {
03814       /* lk addresses always go in the second insn word.  */
03815       mod = ((TOUPPER (operand->buf[1]) == 'A') ? 12 :
03816             (operand->buf[1] == '(') ? 15 :
03817             (strchr (operand->buf, '%') != NULL) ? 14 : 13);
03818       arf = ((mod == 12) ? operand->buf[3] - '0' :
03819             (mod == 15) ? 0 : operand->buf[4] - '0');
03820 
03821       insn->opcode[1].addr_expr = operand->exp;
03822 
03823       if (operand->exp.X_op == O_constant)
03824        insn->opcode[1].word = operand->exp.X_add_number;
03825       else
03826        {
03827          insn->opcode[1].word = 0;
03828          insn->opcode[1].r_nchars = 2;
03829          insn->opcode[1].r_type = BFD_RELOC_TIC54X_16_OF_23;
03830          insn->opcode[1].unresolved = 1;
03831        }
03832     }
03833   else if (strncasecmp (operand->buf, "*sp (", 4) == 0)
03834     {
03835       /* Stack offsets look the same as 7-bit direct addressing.  */
03836       return encode_address (insn, operand);
03837     }
03838   else
03839     {
03840       arf = (TOUPPER (operand->buf[1]) == 'A' ?
03841             operand->buf[3] : operand->buf[4]) - '0';
03842 
03843       if (operand->buf[1] == '+')
03844        {
03845          mod = 3;               /* *+ARx  */
03846          if (insn->tm->flags & FL_SMR)
03847            as_warn (_("Address mode *+ARx is write-only. "
03848                      "Results of reading are undefined."));
03849        }
03850       else if (operand->buf[4] == '\0')
03851        mod = 0;                 /* *ARx  */
03852       else if (operand->buf[5] == '\0')
03853        mod = (operand->buf[4] == '-' ? 1 : 2); /* *ARx+ / *ARx-  */
03854       else if (operand->buf[6] == '\0')
03855        {
03856          if (operand->buf[5] == '0')
03857            mod = (operand->buf[4] == '-' ? 5 : 6); /* *ARx+0 / *ARx-0  */
03858          else
03859            mod = (operand->buf[4] == '-' ? 8 : 10);/* *ARx+% / *ARx-%  */
03860        }
03861       else if (TOUPPER (operand->buf[6]) == 'B')
03862        mod = (operand->buf[4] == '-' ? 4 : 7); /* ARx+0B / *ARx-0B  */
03863       else if (TOUPPER (operand->buf[6]) == '%')
03864        mod = (operand->buf[4] == '-' ? 9 : 11); /* ARx+0% / *ARx - 0%  */
03865       else
03866        {
03867          as_bad (_("Unrecognized indirect address format \"%s\""),
03868                 operand->buf);
03869          return 0;
03870        }
03871     }
03872 
03873   insn->opcode[0].word |= 0x80 | (mod << 3) | arf;
03874 
03875   return 1;
03876 }
03877 
03878 static int
03879 encode_integer (insn, operand, which, min, max, mask)
03880      tic54x_insn *insn;
03881      struct opstruct *operand;
03882      int which;
03883      int min;
03884      int max;
03885      unsigned short mask;
03886 {
03887   long parse, integer;
03888 
03889   insn->opcode[which].addr_expr = operand->exp;
03890 
03891   if (operand->exp.X_op == O_constant)
03892     {
03893       parse = operand->exp.X_add_number;
03894       /* Hack -- fixup for 16-bit hex quantities that get converted positive
03895         instead of negative.  */
03896       if ((parse & 0x8000) && min == -32768 && max == 32767)
03897        integer = (short) parse;
03898       else
03899        integer = parse;
03900 
03901       if (integer >= min && integer <= max)
03902        {
03903          insn->opcode[which].word |= (integer & mask);
03904          return 1;
03905        }
03906       as_bad (_("Operand '%s' out of range (%d <= x <= %d)"),
03907              operand->buf, min, max);
03908     }
03909   else
03910     {
03911       if (insn->opcode[which].addr_expr.X_op == O_constant)
03912        {
03913          insn->opcode[which].word |=
03914            insn->opcode[which].addr_expr.X_add_number & mask;
03915        }
03916       else
03917        {
03918          /* Do the fixup later; just store the expression.  */
03919          bfd_reloc_code_real_type rtype =
03920            (mask == 0x1FF ? BFD_RELOC_TIC54X_PARTMS9 :
03921             mask == 0xFFFF ? BFD_RELOC_TIC54X_16_OF_23 :
03922             mask == 0x7F ? BFD_RELOC_TIC54X_PARTLS7 : BFD_RELOC_8);
03923          int size = (mask == 0x1FF || mask == 0xFFFF) ? 2 : 1;
03924 
03925          if (rtype == BFD_RELOC_8)
03926            as_bad (_("Error in relocation handling"));
03927 
03928          insn->opcode[which].r_nchars = size;
03929          insn->opcode[which].r_type = rtype;
03930          insn->opcode[which].unresolved = 1;
03931        }
03932 
03933       return 1;
03934     }
03935 
03936   return 0;
03937 }
03938 
03939 static int
03940 encode_condition (insn, operand)
03941      tic54x_insn *insn;
03942      struct opstruct *operand;
03943 {
03944   symbol *cc = (symbol *) hash_find (cc_hash, operand->buf);
03945   if (!cc)
03946     {
03947       as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
03948       return 0;
03949     }
03950 #define CC_GROUP 0x40
03951 #define CC_ACC   0x08
03952 #define CATG_A1  0x07
03953 #define CATG_B1  0x30
03954 #define CATG_A2  0x30
03955 #define CATG_B2  0x0C
03956 #define CATG_C2  0x03
03957   /* Disallow group 1 conditions mixed with group 2 conditions
03958      if group 1, allow only one category A and one category B
03959      if group 2, allow only one each of category A, B, and C.  */
03960   if (((insn->opcode[0].word & 0xFF) != 0))
03961     {
03962       if ((insn->opcode[0].word & CC_GROUP) != (cc->value & CC_GROUP))
03963        {
03964          as_bad (_("Condition \"%s\" does not match preceding group"),
03965                 operand->buf);
03966          return 0;
03967        }
03968       if (insn->opcode[0].word & CC_GROUP)
03969        {
03970          if ((insn->opcode[0].word & CC_ACC) != (cc->value & CC_ACC))
03971            {
03972              as_bad (_("Condition \"%s\" uses a different accumulator from "
03973                      "a preceding condition"),
03974                     operand->buf);
03975              return 0;
03976            }
03977          if ((insn->opcode[0].word & CATG_A1) && (cc->value & CATG_A1))
03978            {
03979              as_bad (_("Only one comparison conditional allowed"));
03980              return 0;
03981            }
03982          if ((insn->opcode[0].word & CATG_B1) && (cc->value & CATG_B1))
03983            {
03984              as_bad (_("Only one overflow conditional allowed"));
03985              return 0;
03986            }
03987        }
03988       else if (   ((insn->opcode[0].word & CATG_A2) && (cc->value & CATG_A2))
03989               || ((insn->opcode[0].word & CATG_B2) && (cc->value & CATG_B2))
03990               || ((insn->opcode[0].word & CATG_C2) && (cc->value & CATG_C2)))
03991        {
03992          as_bad (_("Duplicate %s conditional"), operand->buf);
03993          return 0;
03994        }
03995     }
03996 
03997   insn->opcode[0].word |= cc->value;
03998   return 1;
03999 }
04000 
04001 static int
04002 encode_cc3 (insn, operand)
04003      tic54x_insn *insn;
04004      struct opstruct *operand;
04005 {
04006   symbol *cc3 = (symbol *) hash_find (cc3_hash, operand->buf);
04007   int value = cc3 ? cc3->value : operand->exp.X_add_number << 8;
04008 
04009   if ((value & 0x0300) != value)
04010     {
04011       as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
04012       return 0;
04013     }
04014   insn->opcode[0].word |= value;
04015   return 1;
04016 }
04017 
04018 static int
04019 encode_arx (insn, operand)
04020      tic54x_insn *insn;
04021      struct opstruct *operand;
04022 {
04023   int arf = strlen (operand->buf) >= 3 ? operand->buf[2] - '0' : -1;
04024 
04025   if (strncasecmp ("ar", operand->buf, 2) || arf < 0 || arf > 7)
04026     {
04027       as_bad (_("Invalid auxiliary register (use AR0-AR7)"));
04028       return 0;
04029     }
04030   insn->opcode[0].word |= arf;
04031   return 1;
04032 }
04033 
04034 static int
04035 encode_cc2 (insn, operand)
04036      tic54x_insn *insn;
04037      struct opstruct *operand;
04038 {
04039   symbol *cc2 = (symbol *) hash_find (cc2_hash, operand->buf);
04040 
04041   if (!cc2)
04042     {
04043       as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
04044       return 0;
04045     }
04046   insn->opcode[0].word |= cc2->value;
04047   return 1;
04048 }
04049 
04050 static int
04051 encode_operand (insn, type, operand)
04052      tic54x_insn *insn;
04053      enum optype type;
04054      struct opstruct *operand;
04055 {
04056   int ext = (insn->tm->flags & FL_EXT) != 0;
04057 
04058   if (type == OP_MMR && operand->exp.X_op != O_constant)
04059     {
04060       /* Disallow long-constant addressing for memory-mapped addressing.  */
04061       if (insn->is_lkaddr)
04062        {
04063          as_bad (_("lk addressing modes are invalid for memory-mapped "
04064                   "register addressing"));
04065          return 0;
04066        }
04067       type = OP_Smem;
04068       /* Warn about *+ARx when used with MMR operands.  */
04069       if (strncasecmp (operand->buf, "*+ar", 4) == 0)
04070        {
04071          as_warn (_("Address mode *+ARx is not allowed in memory-mapped "
04072                    "register addressing.  Resulting behavior is "
04073                    "undefined."));
04074        }
04075     }
04076 
04077   switch (type)
04078     {
04079     case OP_None:
04080       return 1;
04081     case OP_dmad:
04082       /* 16-bit immediate value.  */
04083       return encode_dmad (insn, operand, 0);
04084     case OP_SRC:
04085       if (TOUPPER (*operand->buf) == 'B')
04086        {
04087          insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 9);
04088          if (insn->using_default_dst)
04089            insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
04090        }
04091       return 1;
04092     case OP_RND:
04093       /* Make sure this agrees with the OP_DST operand.  */
04094       if (!((TOUPPER (operand->buf[0]) == 'B') ^
04095            ((insn->opcode[0].word & (1 << 8)) != 0)))
04096        {
04097          as_bad (_("Destination accumulator for each part of this parallel "
04098                   "instruction must be different"));
04099          return 0;
04100        }
04101       return 1;
04102     case OP_SRC1:
04103     case OP_DST:
04104       if (TOUPPER (operand->buf[0]) == 'B')
04105        insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
04106       return 1;
04107     case OP_Xmem:
04108     case OP_Ymem:
04109       {
04110        int mod = (operand->buf[4] == '\0' ? 0 : /* *arx  */
04111                  operand->buf[4] == '-' ? 1 : /* *arx-  */
04112                  operand->buf[5] == '\0' ? 2 : 3); /* *arx+, *arx+0%  */
04113        int arf = operand->buf[3] - '0' - 2;
04114        int code = (mod << 2) | arf;
04115        insn->opcode[0].word |= (code << (type == OP_Xmem ? 4 : 0));
04116        return 1;
04117       }
04118     case OP_Lmem:
04119     case OP_Smem:
04120       if (!is_indirect (operand))
04121        return encode_address (insn, operand);
04122       /* Fall through.  */
04123     case OP_Sind:
04124       return encode_indirect (insn, operand);
04125     case OP_xpmad_ms7:
04126       return encode_dmad (insn, operand, 2);
04127     case OP_xpmad:
04128       return encode_dmad (insn, operand, 1);
04129     case OP_PA:
04130     case OP_pmad:
04131       return encode_dmad (insn, operand, 0);
04132     case OP_ARX:
04133       return encode_arx (insn, operand);
04134     case OP_MMRX:
04135     case OP_MMRY:
04136     case OP_MMR:
04137       {
04138        int value = operand->exp.X_add_number;
04139 
04140        if (type == OP_MMR)
04141          insn->opcode[0].word |= value;
04142        else
04143          {
04144            if (value < 16 || value > 24)
04145              {
04146               as_bad (_("Memory mapped register \"%s\" out of range"),
04147                      operand->buf);
04148               return 0;
04149              }
04150            if (type == OP_MMRX)
04151              insn->opcode[0].word |= (value - 16) << 4;
04152            else
04153              insn->opcode[0].word |= (value - 16);
04154          }
04155        return 1;
04156       }
04157     case OP_B:
04158     case OP_A:
04159       return 1;
04160     case OP_SHFT:
04161       return encode_integer (insn, operand, ext + insn->is_lkaddr,
04162                           0, 15, 0xF);
04163     case OP_SHIFT:
04164       return encode_integer (insn, operand, ext + insn->is_lkaddr,
04165                           -16, 15, 0x1F);
04166     case OP_lk:
04167       return encode_integer (insn, operand, 1 + insn->is_lkaddr,
04168                           -32768, 32767, 0xFFFF);
04169     case OP_CC:
04170       return encode_condition (insn, operand);
04171     case OP_CC2:
04172       return encode_cc2 (insn, operand);
04173     case OP_CC3:
04174       return encode_cc3 (insn, operand);
04175     case OP_BITC:
04176       return encode_integer (insn, operand, 0, 0, 15, 0xF);
04177     case OP_k8:
04178       return encode_integer (insn, operand, 0, -128, 127, 0xFF);
04179     case OP_123:
04180       {
04181        int value = operand->exp.X_add_number;
04182        int code;
04183        if (value < 1 || value > 3)
04184          {
04185            as_bad (_("Invalid operand (use 1, 2, or 3)"));
04186            return 0;
04187          }
04188        code = value == 1 ? 0 : value == 2 ? 0x2 : 0x1;
04189        insn->opcode[0].word |= (code << 8);
04190        return 1;
04191       }
04192     case OP_031:
04193       return encode_integer (insn, operand, 0, 0, 31, 0x1F);
04194     case OP_k8u:
04195       return encode_integer (insn, operand, 0, 0, 255, 0xFF);
04196     case OP_lku:
04197       return encode_integer (insn, operand, 1 + insn->is_lkaddr,
04198                           0, 65535, 0xFFFF);
04199     case OP_SBIT:
04200       {
04201        symbol *sbit = (symbol *) hash_find (sbit_hash, operand->buf);
04202        int value = is_absolute (operand) ?
04203          operand->exp.X_add_number : (sbit ? sbit->value : -1);
04204        int reg = 0;
04205 
04206        if (insn->opcount == 1)
04207          {
04208            if (!sbit)
04209              {
04210               as_bad (_("A status register or status bit name is required"));
04211               return 0;
04212              }
04213            /* Guess the register based on the status bit; "ovb" is the last
04214               status bit defined for st0.  */
04215            if (sbit > (symbol *) hash_find (sbit_hash, "ovb"))
04216              reg = 1;
04217          }
04218        if (value == -1)
04219          {
04220            as_bad (_("Unrecognized status bit \"%s\""), operand->buf);
04221            return 0;
04222          }
04223        insn->opcode[0].word |= value;
04224        insn->opcode[0].word |= (reg << 9);
04225        return 1;
04226       }
04227     case OP_N:
04228       if (strcasecmp (operand->buf, "st0") == 0
04229          || strcasecmp (operand->buf, "st1") == 0)
04230        {
04231          insn->opcode[0].word |=
04232            ((unsigned short) (operand->buf[2] - '0')) << 9;
04233          return 1;
04234        }
04235       else if (operand->exp.X_op == O_constant
04236               && (operand->exp.X_add_number == 0
04237                  || operand->exp.X_add_number == 1))
04238        {
04239          insn->opcode[0].word |=
04240            ((unsigned short) (operand->exp.X_add_number)) << 9;
04241          return 1;
04242        }
04243       as_bad (_("Invalid status register \"%s\""), operand->buf);
04244       return 0;
04245     case OP_k5:
04246       return encode_integer (insn, operand, 0, -16, 15, 0x1F);
04247     case OP_k3:
04248       return encode_integer (insn, operand, 0, 0, 7, 0x7);
04249     case OP_k9:
04250       return encode_integer (insn, operand, 0, 0, 0x1FF, 0x1FF);
04251     case OP_12:
04252       if (operand->exp.X_add_number != 1
04253          && operand->exp.X_add_number != 2)
04254        {
04255          as_bad (_("Operand \"%s\" out of range (use 1 or 2)"), operand->buf);
04256          return 0;
04257        }
04258       insn->opcode[0].word |= (operand->exp.X_add_number - 1) << 9;
04259       return 1;
04260     case OP_16:
04261     case OP_T:
04262     case OP_TS:
04263     case OP_ASM:
04264     case OP_TRN:
04265     case OP_DP:
04266     case OP_ARP:
04267       /* No encoding necessary.  */
04268       return 1;
04269     default:
04270       return 0;
04271     }
04272 
04273   return 1;
04274 }
04275 
04276 static void
04277 emit_insn (insn)
04278      tic54x_insn *insn;
04279 {
04280   int i;
04281   flagword oldflags = bfd_get_section_flags (stdoutput, now_seg);
04282   flagword flags = oldflags | SEC_CODE;
04283 
04284   if (! bfd_set_section_flags (stdoutput, now_seg, flags))
04285         as_warn (_("error setting flags for \"%s\": %s"),
04286                  bfd_section_name (stdoutput, now_seg),
04287                  bfd_errmsg (bfd_get_error ()));
04288 
04289   for (i = 0; i < insn->words; i++)
04290     {
04291       int size = (insn->opcode[i].unresolved
04292                 && insn->opcode[i].r_type == BFD_RELOC_TIC54X_23) ? 4 : 2;
04293       char *p = frag_more (size);
04294 
04295       if (size == 2)
04296        md_number_to_chars (p, (valueT) insn->opcode[i].word, 2);
04297       else
04298        md_number_to_chars (p, (valueT) insn->opcode[i].word << 16, 4);
04299 
04300       if (insn->opcode[i].unresolved)
04301        fix_new_exp (frag_now, p - frag_now->fr_literal,
04302                    insn->opcode[i].r_nchars, &insn->opcode[i].addr_expr,
04303                    FALSE, insn->opcode[i].r_type);
04304     }
04305 }
04306 
04307 /* Convert the operand strings into appropriate opcode values
04308    return the total number of words used by the instruction.  */
04309 
04310 static int
04311 build_insn (insn)
04312      tic54x_insn *insn;
04313 {
04314   int i;
04315 
04316   /* Only non-parallel instructions support lk addressing.  */
04317   if (!(insn->tm->flags & FL_PAR))
04318     {
04319       for (i = 0; i < insn->opcount; i++)
04320        {
04321          if ((OPTYPE (insn->operands[i].type) == OP_Smem
04322               || OPTYPE (insn->operands[i].type) == OP_Lmem
04323               || OPTYPE (insn->operands[i].type) == OP_Sind)
04324              && strchr (insn->operands[i].buf, '(')
04325              /* Don't mistake stack-relative addressing for lk addressing.  */
04326              && strncasecmp (insn->operands[i].buf, "*sp (", 4) != 0)
04327            {
04328              insn->is_lkaddr = 1;
04329              insn->lkoperand = i;
04330              break;
04331            }
04332        }
04333     }
04334   insn->words = insn->tm->words + insn->is_lkaddr;
04335 
04336   insn->opcode[0].word = insn->tm->opcode;
04337   if (insn->tm->flags & FL_EXT)
04338     insn->opcode[1 + insn->is_lkaddr].word = insn->tm->opcode2;
04339 
04340   for (i = 0; i < insn->opcount; i++)
04341     {
04342       enum optype type = insn->operands[i].type;
04343 
04344       if (!encode_operand (insn, type, &insn->operands[i]))
04345        return 0;
04346     }
04347   if (insn->tm->flags & FL_PAR)
04348     for (i = 0; i < insn->paropcount; i++)
04349       {
04350        enum optype partype = insn->paroperands[i].type;
04351 
04352        if (!encode_operand (insn, partype, &insn->paroperands[i]))
04353          return 0;
04354       }
04355 
04356   emit_insn (insn);
04357 
04358   return insn->words;
04359 }
04360 
04361 static int
04362 optimize_insn (insn)
04363      tic54x_insn *insn;
04364 {
04365   /* Optimize some instructions, helping out the brain-dead programmer.  */
04366 #define is_zero(op) ((op).exp.X_op == O_constant && (op).exp.X_add_number == 0)
04367   if (strcasecmp (insn->tm->name, "add") == 0)
04368     {
04369       if (insn->opcount > 1
04370          && is_accumulator (&insn->operands[insn->opcount - 2])
04371          && is_accumulator (&insn->operands[insn->opcount - 1])
04372          && strcasecmp (insn->operands[insn->opcount - 2].buf,
04373                       insn->operands[insn->opcount - 1].buf) == 0)
04374        {
04375          --insn->opcount;
04376          insn->using_default_dst = 1;
04377          return 1;
04378        }
04379 
04380       /* Try to collapse if Xmem and shift count is zero.  */
04381       if ((OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
04382           && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT
04383           && is_zero (insn->operands[1]))
04384          /* Or if Smem, shift is zero or absent, and SRC == DST.  */
04385          || (OPTYPE (insn->tm->operand_types[0]) == OP_Smem
04386              && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
04387              && is_type (&insn->operands[1], OP_SHIFT)
04388              && is_zero (insn->operands[1]) && insn->opcount == 3))
04389        {
04390          insn->operands[1] = insn->operands[2];
04391          insn->opcount = 2;
04392          return 1;
04393        }
04394     }
04395   else if (strcasecmp (insn->tm->name, "ld") == 0)
04396     {
04397       if (insn->opcount == 3 && insn->operands[0].type != OP_SRC)
04398        {
04399          if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
04400               || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
04401              && is_zero (insn->operands[1])
04402              && (OPTYPE (insn->tm->operand_types[0]) != OP_lk
04403                 || (insn->operands[0].exp.X_op == O_constant
04404                     && insn->operands[0].exp.X_add_number <= 255
04405                     && insn->operands[0].exp.X_add_number >= 0)))
04406            {
04407              insn->operands[1] = insn->operands[2];
04408              insn->opcount = 2;
04409              return 1;
04410            }
04411        }
04412     }
04413   else if (strcasecmp (insn->tm->name, "sth") == 0
04414           || strcasecmp (insn->tm->name, "stl") == 0)
04415     {
04416       if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
04417           || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
04418          && is_zero (insn->operands[1]))
04419        {
04420          insn->operands[1] = insn->operands[2];
04421          insn->opcount = 2;
04422          return 1;
04423        }
04424     }
04425   else if (strcasecmp (insn->tm->name, "sub") == 0)
04426     {
04427       if (insn->opcount > 1
04428          && is_accumulator (&insn->operands[insn->opcount - 2])
04429          && is_accumulator (&insn->operands[insn->opcount - 1])
04430          && strcasecmp (insn->operands[insn->opcount - 2].buf,
04431                       insn->operands[insn->opcount - 1].buf) == 0)
04432        {
04433          --insn->opcount;
04434          insn->using_default_dst = 1;
04435          return 1;
04436        }
04437 
04438       if (   ((OPTYPE (insn->tm->operand_types[0]) == OP_Smem
04439            && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT)
04440           || (OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
04441            && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT))
04442          && is_zero (insn->operands[1])
04443          && insn->opcount == 3)
04444        {
04445          insn->operands[1] = insn->operands[2];
04446          insn->opcount = 2;
04447          return 1;
04448        }
04449     }
04450   return 0;
04451 }
04452 
04453 /* Find a matching template if possible, and get the operand strings.  */
04454 
04455 static int
04456 tic54x_parse_insn (insn, line)
04457      tic54x_insn *insn;
04458      char *line;
04459 {
04460   insn->tm = (template *) hash_find (op_hash, insn->mnemonic);
04461   if (!insn->tm)
04462     {
04463       as_bad (_("Unrecognized instruction \"%s\""), insn->mnemonic);
04464       return 0;
04465     }
04466 
04467   insn->opcount = get_operands (insn->operands, line);
04468   if (insn->opcount < 0)
04469     return 0;
04470 
04471   /* Check each variation of operands for this mnemonic.  */
04472   while (insn->tm->name && strcasecmp (insn->tm->name, insn->mnemonic) == 0)
04473     {
04474       if (insn->opcount >= insn->tm->minops
04475          && insn->opcount <= insn->tm->maxops
04476          && operands_match (insn, &insn->operands[0], insn->opcount,
04477                           insn->tm->operand_types,
04478                           insn->tm->minops, insn->tm->maxops))
04479        {
04480          /* SUCCESS! now try some optimizations.  */
04481          if (optimize_insn (insn))
04482            {
04483              insn->tm = (template *) hash_find (op_hash,
04484                                            insn->mnemonic);
04485              continue;
04486            }
04487 
04488          return 1;
04489        }
04490       ++(insn->tm);
04491     }
04492   as_bad (_("Unrecognized operand list '%s' for instruction '%s'"),
04493          line, insn->mnemonic);
04494   return 0;
04495 }
04496 
04497 /* We set this in start_line_hook, 'cause if we do a line replacement, we
04498    won't be able to see the next line.  */
04499 static int parallel_on_next_line_hint = 0;
04500 
04501 /* See if this is part of a parallel instruction
04502    Look for a subsequent line starting with "||".  */
04503 
04504 static int
04505 next_line_shows_parallel (next_line)
04506      char *next_line;
04507 {
04508   /* Look for the second half.  */
04509   while (ISSPACE (*next_line))
04510     ++next_line;
04511 
04512   return (next_line[0] == PARALLEL_SEPARATOR
04513          && next_line[1] == PARALLEL_SEPARATOR);
04514 }
04515 
04516 static int
04517 tic54x_parse_parallel_insn_firstline (insn, line)
04518      tic54x_insn *insn;
04519      char *line;
04520 {
04521   insn->tm = (template *) hash_find (parop_hash, insn->mnemonic);
04522   if (!insn->tm)
04523     {
04524       as_bad (_("Unrecognized parallel instruction \"%s\""),
04525              insn->mnemonic);
04526       return 0;
04527     }
04528 
04529   while (insn->tm->name && strcasecmp (insn->tm->name,
04530                                        insn->mnemonic) == 0)
04531     {
04532       insn->opcount = get_operands (insn->operands, line);
04533       if (insn->opcount < 0)
04534        return 0;
04535       if (insn->opcount == 2
04536          && operands_match (insn, &insn->operands[0], insn->opcount,
04537                           insn->tm->operand_types, 2, 2))
04538        {
04539          return 1;
04540        }
04541       ++(insn->tm);
04542     }
04543   /* Didn't find a matching parallel; try for a normal insn.  */
04544   return 0;
04545 }
04546 
04547 /* Parse the second line of a two-line parallel instruction.  */
04548 
04549 static int
04550 tic54x_parse_parallel_insn_lastline (insn, line)
04551      tic54x_insn *insn;
04552      char *line;
04553 {
04554   int valid_mnemonic = 0;
04555 
04556   insn->paropcount = get_operands (insn->paroperands, line);
04557   while (insn->tm->name && strcasecmp (insn->tm->name,
04558                                    insn->mnemonic) == 0)
04559     {
04560       if (strcasecmp (insn->tm->parname, insn->parmnemonic) == 0)
04561        {
04562          valid_mnemonic = 1;
04563 
04564          if (insn->paropcount >= insn->tm->minops
04565              && insn->paropcount <= insn->tm->maxops
04566              && operands_match (insn, insn->paroperands,
04567                              insn->paropcount,
04568                              insn->tm->paroperand_types,
04569                              insn->tm->minops, insn->tm->maxops))
04570            return 1;
04571        }
04572       ++(insn->tm);
04573     }
04574   if (valid_mnemonic)
04575     as_bad (_("Invalid operand (s) for parallel instruction \"%s\""),
04576            insn->parmnemonic);
04577   else
04578     as_bad (_("Unrecognized parallel instruction combination \"%s || %s\""),
04579            insn->mnemonic, insn->parmnemonic);
04580 
04581   return 0;
04582 }
04583 
04584 /* If quotes found, return copy of line up to closing quote;
04585    otherwise up until terminator.
04586    If it's a string, pass as-is; otherwise attempt substitution symbol
04587    replacement on the value.  */
04588 
04589 static char *
04590 subsym_get_arg (line, terminators, str, nosub)
04591      char *line;
04592      char *terminators;
04593      char **str;
04594      int nosub;
04595 {
04596   char *ptr = line;
04597   char *endp;
04598   int is_string = *line == '"';
04599   int is_char = ISDIGIT (*line);
04600 
04601   if (is_char)
04602     {
04603       while (ISDIGIT (*ptr))
04604        ++ptr;
04605       endp = ptr;
04606       *str = xmalloc (ptr - line + 1);
04607       strncpy (*str, line, ptr - line);
04608       (*str)[ptr - line] = 0;
04609     }
04610   else if (is_string)
04611     {
04612       char *savedp = input_line_pointer;
04613       int len;
04614 
04615       input_line_pointer = ptr;
04616       *str = demand_copy_C_string (&len);
04617       endp = input_line_pointer;
04618       input_line_pointer = savedp;
04619 
04620       /* Do forced substitutions if requested.  */
04621       if (!nosub && **str == ':')
04622        *str = subsym_substitute (*str, 1);
04623     }
04624   else
04625     {
04626       char *term = terminators;
04627       char *value = NULL;
04628 
04629       while (*ptr && *ptr != *term)
04630        {
04631          if (!*term)
04632            {
04633              term = terminators;
04634              ++ptr;
04635            }
04636          else
04637            ++term;
04638        }
04639       endp = ptr;
04640       *str = xmalloc (ptr - line + 1);
04641       strncpy (*str, line, ptr - line);
04642       (*str)[ptr - line] = 0;
04643       /* Do simple substitution, if available.  */
04644       if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
04645        *str = value;
04646     }
04647 
04648   return endp;
04649 }
04650 
04651 /* Replace the given substitution string.
04652    We start at the innermost macro level, so that existing locals remain local
04653    Note: we're treating macro args identically to .var's; I don't know if
04654    that's compatible w/TI's assembler.  */
04655 
04656 static void
04657 subsym_create_or_replace (name, value)
04658      char *name;
04659      char *value;
04660 {
04661   int i;
04662 
04663   for (i = macro_level; i > 0; i--)
04664     {
04665       if (hash_find (subsym_hash[i], name))
04666        {
04667          hash_replace (subsym_hash[i], name, value);
04668          return;
04669        }
04670     }
04671   if (hash_find (subsym_hash[0], name))
04672     hash_replace (subsym_hash[0], name, value);
04673   else
04674     hash_insert (subsym_hash[0], name, value);
04675 }
04676 
04677 /* Look up the substitution string replacement for the given symbol.
04678    Start with the innermost macro substitution table given and work
04679    outwards.  */
04680 
04681 static char *
04682 subsym_lookup (name, nest_level)
04683      char *name;
04684      int nest_level;
04685 {
04686   char *value = hash_find (subsym_hash[nest_level], name);
04687 
04688   if (value || nest_level == 0)
04689     return value;
04690 
04691   return subsym_lookup (name, nest_level - 1);
04692 }
04693 
04694 /* Do substitution-symbol replacement on the given line (recursively).
04695    return the argument if no substitution was done
04696 
04697    Also look for built-in functions ($func (arg)) and local labels.
04698 
04699    If FORCED is set, look for forced substitutions of the form ':SYMBOL:'.  */
04700 
04701 static char *
04702 subsym_substitute (line, forced)
04703      char * line;
04704      int forced;
04705 {
04706   /* For each apparent symbol, see if it's a substitution symbol, and if so,
04707      replace it in the input.  */
04708   char *replacement; /* current replacement for LINE.  */
04709   char *head; /* Start of line.  */
04710   char *ptr; /* Current examination point.  */
04711   int changed = 0; /* Did we make a substitution?  */
04712   int eval_line = 0; /* Is this line a .eval/.asg statement?  */
04713   int eval_symbol = 0; /* Are we in the middle of the symbol for
04714                           .eval/.asg?  */
04715   char *eval_end = NULL;
04716   int recurse = 1;
04717   int line_conditional = 0;
04718   char *tmp;
04719 
04720   /* Work with a copy of the input line.  */
04721   replacement = xmalloc (strlen (line) + 1);
04722   strcpy (replacement, line);
04723 
04724   ptr = head = replacement;
04725 
04726   /* Flag lines where we might need to replace a single '=' with two;
04727      GAS uses single '=' to assign macro args values, and possibly other
04728      places, so limit what we replace.  */
04729   if (strstr (line, ".if")
04730       || strstr (line, ".elseif")
04731       || strstr (line, ".break"))
04732     line_conditional = 1;
04733 
04734   /* Watch out for .eval, so that we avoid doing substitution on the
04735      symbol being assigned a value.  */
04736   if (strstr (line, ".eval") || strstr (line, ".asg"))
04737     eval_line = 1;
04738 
04739   /* If it's a macro definition, don't do substitution on the argument
04740      names.  */
04741   if (strstr (line, ".macro"))
04742     return line;
04743 
04744   while (!is_end_of_line[(int) *ptr])
04745     {
04746       int current_char = *ptr;
04747 
04748       /* Need to update this since LINE may have been modified.  */
04749       if (eval_line)
04750        eval_end = strrchr (ptr, ',');
04751 
04752       /* Replace triple double quotes with bounding quote/escapes.  */
04753       if (current_char == '"' && ptr[1] == '"' && ptr[2] == '"')
04754        {
04755          ptr[1] = '\\';
04756          tmp = strstr (ptr + 2, "\"\"\"");
04757          if (tmp)
04758            tmp[0] = '\\';
04759          changed = 1;
04760        }
04761 
04762       /* Replace a single '=' with a '==';
04763         for compatibility with older code only.  */
04764       if (line_conditional && current_char == '=')
04765        {
04766          if (ptr[1] == '=')
04767            {
04768              ptr += 2;
04769              continue;
04770            }
04771          *ptr++ = '\0';
04772          tmp = xmalloc (strlen (head) + 2 + strlen (ptr) + 1);
04773          sprintf (tmp, "%s==%s", head, ptr);
04774          /* Continue examining after the '=='.  */
04775          ptr = tmp + strlen (head) + 2;
04776          free (replacement);
04777          head = replacement = tmp;
04778          changed = 1;
04779        }
04780 
04781       /* Flag when we've reached the symbol part of .eval/.asg.  */
04782       if (eval_line && ptr >= eval_end)
04783        eval_symbol = 1;
04784 
04785       /* For each apparent symbol, see if it's a substitution symbol, and if
04786         so, replace it in the input.  */
04787       if ((forced && current_char == ':')
04788          || (!forced && is_name_beginner (current_char)))
04789        {
04790          char *name; /* Symbol to be replaced.  */
04791          char *savedp = input_line_pointer;
04792          int c;
04793          char *value = NULL;
04794          char *tail; /* Rest of line after symbol.  */
04795 
04796          /* Skip the colon.  */
04797          if (forced)
04798            ++ptr;
04799 
04800          name = input_line_pointer = ptr;
04801          c = get_symbol_end ();
04802          /* '?' is not normally part of a symbol, but it IS part of a local
04803             label.  */
04804          if (c == '?')
04805            {
04806              *input_line_pointer++ = c;
04807              c = *input_line_pointer;
04808              *input_line_pointer = '\0';
04809            }
04810          /* Avoid infinite recursion; if a symbol shows up a second time for
04811             substitution, leave it as is.  */
04812          if (hash_find (subsym_recurse_hash, name) == NULL)
04813            value = subsym_lookup (name, macro_level);
04814          else
04815            as_warn (_("%s symbol recursion stopped at "
04816                      "second appearance of '%s'"),
04817                    forced ? "Forced substitution" : "Substitution", name);
04818          ptr = tail = input_line_pointer;
04819          input_line_pointer = savedp;
04820 
04821          /* Check for local labels; replace them with the appropriate
04822             substitution.  */
04823          if ((*name == '$' && ISDIGIT (name[1]) && name[2] == '\0')
04824              || name[strlen (name) - 1] == '?')
04825            {
04826              /* Use an existing identifier for that label if, available, or
04827                create a new, unique identifier.  */
04828              value = hash_find (local_label_hash[macro_level], name);
04829              if (value == NULL)
04830               {
04831                 char digit[11];
04832                 char *namecopy = strcpy (xmalloc (strlen (name) + 1), name);
04833 
04834                 value = strcpy (xmalloc (strlen (name) + sizeof (digit) + 1),
04835                               name);
04836                 if (*value != '$')
04837                   value[strlen (value) - 1] = '\0';
04838                 sprintf (digit, ".%d", local_label_id++);
04839                 strcat (value, digit);
04840                 hash_insert (local_label_hash[macro_level], namecopy, value);
04841               }
04842              /* Indicate where to continue looking for substitutions.  */
04843              ptr = tail;
04844            }
04845          /* Check for built-in subsym and math functions.  */
04846          else if (value != NULL && *name == '$')
04847            {
04848              subsym_proc_entry *entry = (subsym_proc_entry *) value;
04849              math_proc_entry *math_entry = hash_find (math_hash, name);
04850              char *arg1, *arg2 = NULL;
04851 
04852              *ptr = c;
04853              if (entry == NULL)
04854               {
04855                 as_bad (_("Unrecognized substitution symbol function"));
04856                 break;
04857               }
04858              else if (*ptr != '(')
04859               {
04860                 as_bad (_("Missing '(' after substitution symbol function"));
04861                 break;
04862               }
04863              ++ptr;
04864              if (math_entry != NULL)
04865               {
04866                 float arg1, arg2 = 0;
04867                 volatile float fresult;
04868 
04869                 arg1 = (float) strtod (ptr, &ptr);
04870                 if (math_entry->nargs == 2)
04871                   {
04872                     if (*ptr++ != ',')
04873                      {
04874                        as_bad (_("Expecting second argument"));
04875                        break;
04876                      }
04877                     arg2 = (float) strtod (ptr, &ptr);
04878                   }
04879                 fresult = (*math_entry->proc) (arg1, arg2);
04880                 value = xmalloc (128);
04881                 if (math_entry->int_return)
04882                   sprintf (value, "%d", (int) fresult);
04883                 else
04884                   sprintf (value, "%f", fresult);
04885                 if (*ptr++ != ')')
04886                   {
04887                     as_bad (_("Extra junk in function call, expecting ')'"));
04888                     break;
04889                   }
04890                 /* Don't bother recursing; the replacement isn't a
04891                      symbol.  */
04892                 recurse = 0;
04893               }
04894              else
04895               {
04896                 int val;
04897                 int arg_type[2] = { *ptr == '"' , 0 };
04898                 int ismember = !strcmp (entry->name, "$ismember");
04899 
04900                 /* Parse one or two args, which must be a substitution
04901                    symbol, string or a character-string constant.  */
04902                 /* For all functions, a string or substitution symbol may be
04903                    used, with the following exceptions:
04904                    firstch/lastch: 2nd arg must be character constant
04905                    ismember: both args must be substitution symbols.  */
04906                 ptr = subsym_get_arg (ptr, ",)", &arg1, ismember);
04907                 if (!arg1)
04908                   break;
04909                 if (entry->nargs == 2)
04910                   {
04911                     if (*ptr++ != ',')
04912                      {
04913                        as_bad (_("Function expects two arguments"));
04914                        break;
04915                      }
04916                     /* Character constants are converted to numerics
04917                       by the preprocessor.  */
04918                     arg_type[1] = (ISDIGIT (*ptr)) ? 2 : (*ptr == '"');
04919                     ptr = subsym_get_arg (ptr, ")", &arg2, ismember);
04920                   }
04921                 /* Args checking.  */
04922                 if ((!strcmp (entry->name, "$firstch")
04923                      || !strcmp (entry->name, "$lastch"))
04924                     && arg_type[1] != 2)
04925                   {
04926                     as_bad (_("Expecting character constant argument"));
04927                     break;
04928                   }
04929                 if (ismember
04930                     && (arg_type[0] != 0 || arg_type[1] != 0))
04931                   {
04932                     as_bad (_("Both arguments must be substitution symbols"));
04933                     break;
04934                   }
04935                 if (*ptr++ != ')')
04936                   {
04937                     as_bad (_("Extra junk in function call, expecting ')'"));
04938                     break;
04939                   }
04940                 val = (*entry->proc) (arg1, arg2);
04941                 value = xmalloc (64);
04942                 sprintf (value, "%d", val);
04943               }
04944              /* Fix things up to replace the entire expression, not just the
04945                function name.  */
04946              tail = ptr;
04947              c = *tail;
04948            }
04949 
04950          if (value != NULL && !eval_symbol)
04951            {
04952              /* Replace the symbol with its string replacement and
04953                continue.  Recursively replace VALUE until either no
04954                substitutions are performed, or a substitution that has been
04955                previously made is encountered again.
04956 
04957                put the symbol into the recursion hash table so we only
04958                try to replace a symbol once.  */
04959              if (recurse)
04960               {
04961                 hash_insert (subsym_recurse_hash, name, name);
04962                 value = subsym_substitute (value, macro_level > 0);
04963                 hash_delete (subsym_recurse_hash, name);
04964               }
04965 
04966              /* Temporarily zero-terminate where the symbol started.  */
04967              *name = 0;
04968              if (forced)
04969               {
04970                 if (c == '(')
04971                   {
04972                     /* Subscripted substitution symbol -- use just the
04973                       indicated portion of the string; the description
04974                       kinda indicates that forced substitution is not
04975                       supposed to be recursive, but I'm not sure.  */
04976                     unsigned beg, len = 1; /* default to a single char */
04977                     char *newval = strcpy (xmalloc (strlen (value) + 1),
04978                                         value);
04979 
04980                     savedp = input_line_pointer;
04981                     input_line_pointer = tail + 1;
04982                     beg = get_absolute_expression ();
04983                     if (beg < 1)
04984                      {
04985                        as_bad (_("Invalid subscript (use 1 to %d)"),
04986                               (int) strlen (value));
04987                        break;
04988                      }
04989                     if (*input_line_pointer == ',')
04990                      {
04991                        ++input_line_pointer;
04992                        len = get_absolute_expression ();
04993                        if (beg + len > strlen (value))
04994                          {
04995                            as_bad (_("Invalid length (use 0 to %d"),
04996                                   (int) strlen (value) - beg);
04997                            break;
04998                          }
04999                      }
05000                     newval += beg - 1;
05001                     newval[len] = 0;
05002                     tail = input_line_pointer;
05003                     if (*tail++ != ')')
05004                      {
05005                        as_bad (_("Missing ')' in subscripted substitution "
05006                                 "symbol expression"));
05007                        break;
05008                      }
05009                     c = *tail;
05010                     input_line_pointer = savedp;
05011 
05012                     value = newval;
05013                   }
05014                 name[-1] = 0;
05015               }
05016              tmp = xmalloc (strlen (head) + strlen (value) +
05017                           strlen (tail + 1) + 2);
05018              strcpy (tmp, head);
05019              strcat (tmp, value);
05020              /* Make sure forced substitutions are properly terminated.  */
05021              if (forced)
05022               {
05023                 if (c != ':')
05024                   {
05025                     as_bad (_("Missing forced substitution terminator ':'"));
05026                     break;
05027                   }
05028                 ++tail;
05029               }
05030              else
05031               /* Restore the character after the symbol end.  */
05032               *tail = c;
05033              strcat (tmp, tail);
05034              /* Continue examining after the replacement value.  */
05035              ptr = tmp + strlen (head) + strlen (value);
05036              free (replacement);
05037              head = replacement = tmp;
05038              changed = 1;
05039            }
05040          else
05041            *ptr = c;
05042        }
05043       else
05044        {
05045          ++ptr;
05046        }
05047     }
05048 
05049   if (changed)
05050     return replacement;
05051   else
05052     return line;
05053 }
05054 
05055 /* We use this to handle substitution symbols
05056    hijack input_line_pointer, replacing it with our substituted string.
05057 
05058    .sslist should enable listing the line after replacements are made...
05059 
05060    returns the new buffer limit.  */
05061 
05062 void
05063 tic54x_start_line_hook ()
05064 {
05065   char *line, *endp;
05066   char *replacement = NULL;
05067 
05068   /* Work with a copy of the input line, including EOL char.  */
05069   endp = input_line_pointer;
05070   while (!is_end_of_line[(int) *endp++])
05071     ;
05072   line = xmalloc (endp - input_line_pointer + 1);
05073   strncpy (line, input_line_pointer, endp - input_line_pointer + 1);
05074   line[endp - input_line_pointer] = 0;
05075 
05076   /* Scan ahead for parallel insns.  */
05077   parallel_on_next_line_hint = next_line_shows_parallel (endp + 1);
05078 
05079   /* If within a macro, first process forced replacements.  */
05080   if (macro_level > 0)
05081     replacement = subsym_substitute (line, 1);
05082   else
05083     replacement = line;
05084   replacement = subsym_substitute (replacement, 0);
05085 
05086   if (replacement != line)
05087     {
05088       char *tmp = replacement;
05089       char *comment = strchr (replacement, ';');
05090       char endc = replacement[strlen (replacement) - 1];
05091 
05092       /* Clean up the replacement; we'd prefer to have this done by the
05093         standard preprocessing equipment (maybe do_scrub_chars?)
05094         but for now, do a quick-and-dirty.  */
05095       if (comment != NULL)
05096        {
05097          comment[0] = endc;
05098          comment[1] = 0;
05099          --comment;
05100        }
05101       else
05102        comment = replacement + strlen (replacement) - 1;
05103 
05104       /* Trim trailing whitespace.  */
05105       while (ISSPACE (*comment))
05106        {
05107          comment[0] = endc;
05108          comment[1] = 0;
05109          --comment;
05110        }
05111 
05112       /* Compact leading whitespace.  */
05113       while (ISSPACE (tmp[0]) && ISSPACE (tmp[1]))
05114        ++tmp;
05115 
05116       input_line_pointer = endp;
05117       input_scrub_insert_line (tmp);
05118       free (replacement);
05119       free (line);
05120       /* Keep track of whether we've done a substitution.  */
05121       substitution_line = 1;
05122     }
05123   else
05124     {
05125       /* No change.  */
05126       free (line);
05127       substitution_line = 0;
05128     }
05129 }
05130 
05131 /* This is the guts of the machine-dependent assembler.  STR points to a
05132    machine dependent instruction.  This function is supposed to emit
05133    the frags/bytes it assembles to.  */
05134 void
05135 md_assemble (line)
05136      char *line;
05137 {
05138   static int repeat_slot = 0;
05139   static int delay_slots = 0; /* How many delay slots left to fill?  */
05140   static int is_parallel = 0;
05141   static tic54x_insn insn;
05142   char *lptr;
05143   char *savedp = input_line_pointer;
05144   int c;
05145 
05146   input_line_pointer = line;
05147   c = get_symbol_end ();
05148 
05149   if (cpu == VNONE)
05150     cpu = V542;
05151   if (address_mode_needs_set)
05152     {
05153       set_address_mode (amode);
05154       address_mode_needs_set = 0;
05155     }
05156   if (cpu_needs_set)
05157     {
05158       set_cpu (cpu);
05159       cpu_needs_set = 0;
05160     }
05161   assembly_begun = 1;
05162 
05163   if (is_parallel)
05164     {
05165       is_parallel = 0;
05166 
05167       strcpy (insn.parmnemonic, line);
05168       lptr = input_line_pointer;
05169       *lptr = c;
05170       input_line_pointer = savedp;
05171 
05172       if (tic54x_parse_parallel_insn_lastline (&insn, lptr))
05173        {
05174          int words = build_insn (&insn);
05175 
05176          if (delay_slots != 0)
05177            {
05178              if (words > delay_slots)
05179               {
05180                 as_bad (_("Instruction does not fit in available delay "
05181                          "slots (%d-word insn, %d slots left)"),
05182                        words, delay_slots);
05183                 delay_slots = 0;
05184                 return;
05185               }
05186              delay_slots -= words;
05187            }
05188        }
05189       return;
05190     }
05191 
05192   memset (&insn, 0, sizeof (insn));
05193   strcpy (insn.mnemonic, line);
05194   lptr = input_line_pointer;
05195   *lptr = c;
05196   input_line_pointer = savedp;
05197 
05198   /* See if this line is part of a parallel instruction; if so, either this
05199      line or the next line will have the "||" specifier preceding the
05200      mnemonic, and we look for it in the parallel insn hash table.  */
05201   if (strstr (line, "||") != NULL || parallel_on_next_line_hint)
05202     {
05203       char *tmp = strstr (line, "||");
05204       if (tmp != NULL)
05205        *tmp = '\0';
05206 
05207       if (tic54x_parse_parallel_insn_firstline (&insn, lptr))
05208        {
05209          is_parallel = 1;
05210          /* If the parallel part is on the same line, process it now,
05211             otherwise let the assembler pick up the next line for us.  */
05212          if (tmp != NULL)
05213            {
05214              while (ISSPACE (tmp[2]))
05215               ++tmp;
05216              md_assemble (tmp + 2);
05217            }
05218        }
05219       else
05220        {
05221          as_bad (_("Unrecognized parallel instruction '%s'"), line);
05222        }
05223       return;
05224     }
05225 
05226   if (tic54x_parse_insn (&insn, lptr))
05227     {
05228       int words;
05229 
05230       if ((insn.tm->flags & FL_LP)
05231          && cpu != V545LP && cpu != V546LP)
05232        {
05233          as_bad (_("Instruction '%s' requires an LP cpu version"),
05234                 insn.tm->name);
05235          return;
05236        }
05237       if ((insn.tm->flags & FL_FAR)
05238          && amode != far_mode)
05239        {
05240          as_bad (_("Instruction '%s' requires far mode addressing"),
05241                 insn.tm->name);
05242          return;
05243        }
05244 
05245       words = build_insn (&insn);
05246 
05247       /* Is this instruction in a delay slot?  */
05248       if (delay_slots)
05249        {
05250          if (words > delay_slots)
05251            {
05252              as_warn (_("Instruction does not fit in available delay "
05253                       "slots (%d-word insn, %d slots left). "
05254                       "Resulting behavior is undefined."),
05255                      words, delay_slots);
05256              delay_slots = 0;
05257              return;
05258            }
05259          /* Branches in delay slots are not allowed.  */
05260          if (insn.tm->flags & FL_BMASK)
05261            {
05262              as_warn (_("Instructions which cause PC discontinuity are not "
05263                       "allowed in a delay slot. "
05264                       "Resulting behavior is undefined."));
05265            }
05266          delay_slots -= words;
05267        }
05268 
05269       /* Is this instruction the target of a repeat?  */
05270       if (repeat_slot)
05271        {
05272          if (insn.tm->flags & FL_NR)
05273            as_warn (_("'%s' is not repeatable. "
05274                      "Resulting behavior is undefined."),
05275                    insn.tm->name);
05276          else if (insn.is_lkaddr)
05277            as_warn (_("Instructions using long offset modifiers or absolute "
05278                      "addresses are not repeatable. "
05279                      "Resulting behavior is undefined."));
05280          repeat_slot = 0;
05281        }
05282 
05283       /* Make sure we check the target of a repeat instruction.  */
05284       if (insn.tm->flags & B_REPEAT)
05285        {
05286          repeat_slot = 1;
05287          /* FIXME -- warn if repeat_slot == 1 at EOF.  */
05288        }
05289       /* Make sure we check our delay slots for validity.  */
05290       if (insn.tm->flags & FL_DELAY)
05291        {
05292          delay_slots = 2;
05293          /* FIXME -- warn if delay_slots != 0 at EOF.  */
05294        }
05295     }
05296 }
05297 
05298 /* Do a final adjustment on the symbol table; in this case, make sure we have
05299    a ".file" symbol.  */
05300 
05301 void
05302 tic54x_adjust_symtab ()
05303 {
05304   if (symbol_rootP == NULL
05305       || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
05306     {
05307       char *filename;
05308       unsigned lineno;
05309       as_where (&filename, &lineno);
05310       c_dot_file_symbol (filename, 0);
05311     }
05312 }
05313 
05314 /* In order to get gas to ignore any | chars at the start of a line,
05315    this function returns true if a | is found in a line.
05316    This lets us process parallel instructions, which span two lines.  */
05317 
05318 int
05319 tic54x_unrecognized_line (int c)
05320 {
05321   return c == PARALLEL_SEPARATOR;
05322 }
05323 
05324 /* Watch for local labels of the form $[0-9] and [_a-zA-Z][_a-zA-Z0-9]*?
05325    Encode their names so that only we see them and can map them to the
05326    appropriate places.
05327    FIXME -- obviously this isn't done yet.  These locals still show up in the
05328    symbol table.  */
05329 void
05330 tic54x_define_label (sym)
05331      symbolS *sym;
05332 {
05333   /* Just in case we need this later; note that this is not necessarily the
05334      same thing as line_label...
05335      When aligning or assigning labels to fields, sometimes the label is
05336      assigned other than the address at which the label appears.
05337      FIXME -- is this really needed? I think all the proper label assignment
05338      is done in tic54x_cons.  */
05339   last_label_seen = sym;
05340 }
05341 
05342 /* Try to parse something that normal parsing failed at.  */
05343 
05344 symbolS *
05345 tic54x_undefined_symbol (name)
05346      char *name;
05347 {
05348   symbol *sym;
05349 
05350   /* Not sure how to handle predefined symbols.  */
05351   if ((sym = (symbol *) hash_find (cc_hash, name)) != NULL ||
05352       (sym = (symbol *) hash_find (cc2_hash, name)) != NULL ||
05353       (sym = (symbol *) hash_find (cc3_hash, name)) != NULL ||
05354       (sym = (symbol *) hash_find (misc_symbol_hash, name)) != NULL ||
05355       (sym = (symbol *) hash_find (sbit_hash, name)) != NULL)
05356     {
05357       return symbol_new (name, reg_section,
05358                       (valueT) sym->value,
05359                       &zero_address_frag);
05360     }
05361 
05362   if ((sym = (symbol *) hash_find (reg_hash, name)) != NULL ||
05363       (sym = (symbol *) hash_find (mmreg_hash, name)) != NULL ||
05364       !strcasecmp (name, "a") || !strcasecmp (name, "b"))
05365     {
05366       return symbol_new (name, reg_section,
05367                       (valueT) sym ? sym->value : 0,
05368                       &zero_address_frag);
05369     }
05370 
05371   return NULL;
05372 }
05373 
05374 /* Parse a name in an expression before the expression parser takes a stab at
05375    it.  */
05376 
05377 int
05378 tic54x_parse_name (name, exp)
05379      char *name ATTRIBUTE_UNUSED;
05380      expressionS *exp ATTRIBUTE_UNUSED;
05381 {
05382   return 0;
05383 }
05384 
05385 char *
05386 md_atof (type, literalP, sizeP)
05387      int type;
05388      char *literalP;
05389      int *sizeP;
05390 {
05391 #define MAX_LITTLENUMS 2
05392   LITTLENUM_TYPE words[MAX_LITTLENUMS];
05393   LITTLENUM_TYPE *word;
05394   /* Only one precision on the c54x.  */
05395   int prec = 2;
05396   char *t = atof_ieee (input_line_pointer, type, words);
05397   if (t)
05398     input_line_pointer = t;
05399   *sizeP = 4;
05400 
05401   /* Target data is little-endian, but floats are stored
05402      big-"word"ian.  ugh.  */
05403   for (word = words; prec--;)
05404     {
05405       md_number_to_chars (literalP, (long) (*word++), sizeof (LITTLENUM_TYPE));
05406       literalP += sizeof (LITTLENUM_TYPE);
05407     }
05408 
05409   return 0;
05410 }
05411 
05412 arelent *
05413 tc_gen_reloc (section, fixP)
05414      asection *section;
05415      fixS *fixP;
05416 {
05417   arelent *rel;
05418   bfd_reloc_code_real_type code = fixP->fx_r_type;
05419   asymbol *sym = symbol_get_bfdsym (fixP->fx_addsy);
05420 
05421   rel = (arelent *) xmalloc (sizeof (arelent));
05422   rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
05423   *rel->sym_ptr_ptr = sym;
05424   /* We assume that all rel->address are host byte offsets.  */
05425   rel->address = fixP->fx_frag->fr_address + fixP->fx_where;
05426   rel->address /= OCTETS_PER_BYTE;
05427   rel->howto = bfd_reloc_type_lookup (stdoutput, code);
05428   if (!strcmp (sym->name, section->name))
05429     rel->howto += HOWTO_BANK;
05430 
05431   if (!rel->howto)
05432     {
05433       const char *name = S_GET_NAME (fixP->fx_addsy);
05434       if (name == NULL)
05435        name = "<unknown>";
05436       as_fatal ("Cannot generate relocation type for symbol %s, code %s",
05437               name, bfd_get_reloc_code_name (code));
05438       return NULL;
05439     }
05440   return rel;
05441 }
05442 
05443 /* Handle cons expressions.  */
05444 
05445 void
05446 tic54x_cons_fix_new (frag, where, octets, exp)
05447      fragS *frag;
05448      int where;
05449      int octets;
05450      expressionS *exp;
05451 {
05452   bfd_reloc_code_real_type r;
05453 
05454   switch (octets)
05455     {
05456     default:
05457       as_bad (_("Unsupported relocation size %d"), octets);
05458       r = BFD_RELOC_TIC54X_16_OF_23;
05459       break;
05460     case 2:
05461       r = BFD_RELOC_TIC54X_16_OF_23;
05462       break;
05463     case 4:
05464       /* TI assembler always uses this, regardless of addressing mode.  */
05465       if (emitting_long)
05466        r = BFD_RELOC_TIC54X_23;
05467       else
05468        /* We never want to directly generate this; this is provided for
05469           stabs support only.  */
05470        r = BFD_RELOC_32;
05471       break;
05472     }
05473   fix_new_exp (frag, where, octets, exp, 0, r);
05474 }
05475 
05476 /* Attempt to simplify or even eliminate a fixup.
05477    To indicate that a fixup has been eliminated, set fixP->fx_done.
05478 
05479    If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry.   */
05480 
05481 void
05482 md_apply_fix (fixP, valP, seg)
05483      fixS *fixP;
05484      valueT * valP;
05485      segT seg ATTRIBUTE_UNUSED;
05486 {
05487   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
05488   valueT val = * valP;
05489 
05490   switch (fixP->fx_r_type)
05491     {
05492     default:
05493       as_fatal ("Bad relocation type: 0x%02x", fixP->fx_r_type);
05494       return;
05495     case BFD_RELOC_TIC54X_MS7_OF_23:
05496       val = (val >> 16) & 0x7F;
05497       /* Fall through.  */
05498     case BFD_RELOC_TIC54X_16_OF_23:
05499     case BFD_RELOC_16:
05500       bfd_put_16 (stdoutput, val, buf);
05501       /* Indicate what we're actually writing, so that we don't get warnings
05502         about exceeding available space.  */
05503       *valP = val & 0xFFFF;
05504       break;
05505     case BFD_RELOC_TIC54X_PARTLS7:
05506       bfd_put_16 (stdoutput,
05507                 (bfd_get_16 (stdoutput, buf) & 0xFF80) | (val & 0x7F),
05508                 buf);
05509       /* Indicate what we're actually writing, so that we don't get warnings
05510         about exceeding available space.  */
05511       *valP = val & 0x7F;
05512       break;
05513     case BFD_RELOC_TIC54X_PARTMS9:
05514       /* TI assembler doesn't shift its encoding for relocatable files, and is
05515         thus incompatible with this implementation's relocatable files.  */
05516       bfd_put_16 (stdoutput,
05517                 (bfd_get_16 (stdoutput, buf) & 0xFE00) | (val >> 7),
05518                 buf);
05519       break;
05520     case BFD_RELOC_32:
05521     case BFD_RELOC_TIC54X_23:
05522       bfd_put_32 (stdoutput,
05523                 (bfd_get_32 (stdoutput, buf) & 0xFF800000) | val,
05524                 buf);
05525       break;
05526     }
05527 
05528   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
05529     fixP->fx_done = 1;
05530 }
05531 
05532 /* This is our chance to record section alignment
05533    don't need to do anything here, since BFD does the proper encoding.  */
05534 
05535 valueT
05536 md_section_align (segment, section_size)
05537      segT segment ATTRIBUTE_UNUSED;
05538      valueT section_size;
05539 {
05540   return section_size;
05541 }
05542 
05543 long
05544 md_pcrel_from (fixP)
05545      fixS *fixP ATTRIBUTE_UNUSED;
05546 {
05547   return 0;
05548 }
05549 
05550 /* Mostly little-endian, but longwords (4 octets) get MS word stored
05551    first.  */
05552 
05553 void
05554 tic54x_number_to_chars (buf, val, n)
05555      char *buf;
05556      valueT val;
05557      int n;
05558 {
05559   if (n != 4)
05560     number_to_chars_littleendian (buf, val, n);
05561   else
05562     {
05563       number_to_chars_littleendian (buf    , val >> 16   , 2);
05564       number_to_chars_littleendian (buf + 2, val & 0xFFFF, 2);
05565     }
05566 }
05567 
05568 int
05569 tic54x_estimate_size_before_relax (frag, seg)
05570      fragS *frag ATTRIBUTE_UNUSED;
05571      segT seg ATTRIBUTE_UNUSED;
05572 {
05573   return 0;
05574 }
05575 
05576 /* We use this to handle bit allocations which we couldn't handle before due
05577    to symbols being in different frags.  return number of octets added.  */
05578 
05579 int
05580 tic54x_relax_frag (frag, stretch)
05581      fragS *frag;
05582      long stretch ATTRIBUTE_UNUSED;
05583 {
05584   symbolS *sym = frag->fr_symbol;
05585   int growth = 0;
05586   int i;
05587 
05588   if (sym != NULL)
05589     {
05590       struct bit_info *bi = (struct bit_info *) frag->fr_opcode;
05591       int bit_offset = frag_bit_offset (frag_prev (frag, bi->seg), bi->seg);
05592       int size = S_GET_VALUE (sym);
05593       fragS *prev_frag = bit_offset_frag (frag_prev (frag, bi->seg), bi->seg);
05594       int available = 16 - bit_offset;
05595 
05596       if (symbol_get_frag (sym) != &zero_address_frag
05597          || S_IS_COMMON (sym)
05598          || !S_IS_DEFINED (sym))
05599        as_bad_where (frag->fr_file, frag->fr_line,
05600                     _("non-absolute value used with .space/.bes"));
05601 
05602       if (size < 0)
05603        {
05604          as_warn (_("negative value ignored in %s"),
05605                  bi->type == TYPE_SPACE ? ".space" :
05606                  bi->type == TYPE_BES ? ".bes" : ".field");
05607          growth = 0;
05608          frag->tc_frag_data = frag->fr_fix = 0;
05609          return 0;
05610        }
05611 
05612       if (bi->type == TYPE_FIELD)
05613        {
05614          /* Bit fields of 16 or larger will have already been handled.  */
05615          if (bit_offset != 0 && available >= size)
05616            {
05617              char *p = prev_frag->fr_literal;
05618 
05619              valueT value = bi->value;
05620              value <<= available - size;
05621              value |= ((unsigned short) p[1] << 8) | p[0];
05622              md_number_to_chars (p, value, 2);
05623              if ((prev_frag->tc_frag_data += size) == 16)
05624               prev_frag->tc_frag_data = 0;
05625              if (bi->sym)
05626               symbol_set_frag (bi->sym, prev_frag);
05627              /* This frag is no longer used.  */
05628              growth = -frag->fr_fix;
05629              frag->fr_fix = 0;
05630              frag->tc_frag_data = 0;
05631            }
05632          else
05633            {
05634              char *p = frag->fr_literal;
05635 
05636              valueT value = bi->value << (16 - size);
05637              md_number_to_chars (p, value, 2);
05638              if ((frag->tc_frag_data = size) == 16)
05639               frag->tc_frag_data = 0;
05640              growth = 0;
05641            }
05642        }
05643       else
05644        {
05645          if (bit_offset != 0 && bit_offset < 16)
05646            {
05647              if (available >= size)
05648               {
05649                 if ((prev_frag->tc_frag_data += size) == 16)
05650                   prev_frag->tc_frag_data = 0;
05651                 if (bi->sym)
05652                   symbol_set_frag (bi->sym, prev_frag);
05653                 /* This frag is no longer used.  */
05654                 growth = -frag->fr_fix;
05655                 frag->fr_fix = 0;
05656                 frag->tc_frag_data = 0;
05657                 goto getout;
05658               }
05659              if (bi->type == TYPE_SPACE && bi->sym)
05660               symbol_set_frag (bi->sym, prev_frag);
05661              size -= available;
05662            }
05663          growth = (size + 15) / 16 * OCTETS_PER_BYTE - frag->fr_fix;
05664          for (i = 0; i < growth; i++)
05665            frag->fr_literal[i] = 0;
05666          frag->fr_fix = growth;
05667          frag->tc_frag_data = size % 16;
05668          /* Make sure any BES label points to the LAST word allocated.  */
05669          if (bi->type == TYPE_BES && bi->sym)
05670            S_SET_VALUE (bi->sym, frag->fr_fix / OCTETS_PER_BYTE - 1);
05671        }
05672     getout:
05673       frag->fr_symbol = 0;
05674       frag->fr_opcode = 0;
05675       free ((void *) bi);
05676     }
05677   return growth;
05678 }
05679 
05680 void
05681 tic54x_convert_frag (abfd, seg, frag)
05682      bfd *abfd ATTRIBUTE_UNUSED;
05683      segT seg ATTRIBUTE_UNUSED;
05684      fragS *frag;
05685 {
05686   /* Offset is in bytes.  */
05687   frag->fr_offset = (frag->fr_next->fr_address
05688                    - frag->fr_address
05689                    - frag->fr_fix) / frag->fr_var;
05690   if (frag->fr_offset < 0)
05691     {
05692       as_bad_where (frag->fr_file, frag->fr_line,
05693                   _("attempt to .space/.bes backwards? (%ld)"),
05694                   (long) frag->fr_offset);
05695     }
05696   frag->fr_type = rs_space;
05697 }
05698 
05699 /* We need to avoid having labels defined for certain directives/pseudo-ops
05700    since once the label is defined, it's in the symbol table for good.  TI
05701    syntax puts the symbol *before* the pseudo (which is kinda like MRI syntax,
05702    I guess, except I've never seen a definition of MRI syntax).
05703 
05704    C is the character that used to be at *REST, which points to the end of the
05705    label.
05706 
05707    Don't allow labels to start with '.'  */
05708 
05709 int
05710 tic54x_start_label (c, rest)
05711      int c;
05712      char *rest;
05713 {
05714   /* If within .struct/.union, no auto line labels, please.  */
05715   if (current_stag != NULL)
05716     return 0;
05717 
05718   /* Disallow labels starting with "."  */
05719   if (c != ':')
05720     {
05721       char *label = rest;
05722 
05723       while (!is_end_of_line[(int) label[-1]])
05724        --label;
05725       if (*label == '.')
05726        {
05727          as_bad (_("Invalid label '%s'"), label);
05728          return 0;
05729        }
05730     }
05731 
05732   if (is_end_of_line[(int) c])
05733     return 1;
05734 
05735   if (ISSPACE (c))
05736     while (ISSPACE (c = *++rest))
05737       ;
05738   if (c == '.')
05739     {
05740       /* Don't let colon () define a label for any of these...  */
05741       return (strncasecmp (rest, ".tag", 4) != 0 || !ISSPACE (rest[4]))
05742        && (strncasecmp (rest, ".struct", 7) != 0 || !ISSPACE (rest[7]))
05743        && (strncasecmp (rest, ".union", 6) != 0 || !ISSPACE (rest[6]))
05744        && (strncasecmp (rest, ".macro", 6) != 0 || !ISSPACE (rest[6]))
05745        && (strncasecmp (rest, ".set", 4) != 0 || !ISSPACE (rest[4]))
05746        && (strncasecmp (rest, ".equ", 4) != 0 || !ISSPACE (rest[4]));
05747     }
05748 
05749   return 1;
05750 }