📄 tc-tic54x.c
字号:
/* tc-tic54x.c -- Assembly code for the Texas Instruments TMS320C54X Copyright 1999, 2000 Free Software Foundation, Inc. Contributed by Timothy Wall (twall@cygnus.com) This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Texas Instruments TMS320C54X machine specific gas. Written by Timothy Wall (twall@alum.mit.edu). Valuable things to do: Pipeline conflict warnings We encode/decode "ld #_label, dp" differently in relocatable files This means we're not compatible with TI output containing those expressions. We store the upper nine bits; TI stores the lower nine bits. How they recover the original upper nine bits is beyond me. Tests to add to expect testsuite: '=' and '==' with .if, .elseif, and .break Incompatibilities (mostly trivial): We don't allow ''' We fill text section with zeroes instead of "nop"s We don't convert '' or "" to a single instance We don't convert '' to '\0' We don't allow strings with .byte/.half/.short/.long Probably details of the subsym stuff are different TI sets labels to be data type 4 (T_INT); GAS uses T_NULL. */#include <stdlib.h>#include <limits.h>#include <errno.h>#include "as.h"#include "sb.h"#include "macro.h"#include "subsegs.h"#include "struc-symbol.h"#include "opcode/tic54x.h"#include "obj-coff.h"#include <math.h>#define MAX_LINE 256 /* Lines longer than this are truncated by TI's asm. */const char comment_chars[] = ";";const char line_comment_chars[] = ";*#"; /* At column zero only. */const char line_separator_chars[] = ""; /* Not permitted. *//* Characters which indicate that this is a floating point constant. */const char FLT_CHARS[] = "fF";/* Characters that can be used to separate mantissa from exp in FP nums. */const char EXP_CHARS[] = "eE";/* Only word (et al.), align, or conditionals are allowed within .struct/.union. */#define ILLEGAL_WITHIN_STRUCT() \ do \ if (current_stag != NULL) \ { \ as_bad (_("pseudo-op illegal within .struct/.union")); \ return; \ } \ while (0)voidmd_show_usage (stream) FILE *stream;{ fprintf (stream, _("C54x-specific command line options:\n")); fprintf (stream, _("-mfar-mode | -mf Use extended addressing\n")); fprintf (stream, _("-mcpu=<CPU version> Specify the CPU version\n"));#if 0 fprintf (stream, _("-mcoff-version={0|1|2} Select COFF version\n"));#endif fprintf (stream, _("-merrors-to-file <filename>\n")); fprintf (stream, _("-me <filename> Redirect errors to a file\n"));}const char *md_shortopts = "";enum cpu_version{ VNONE = 0, V541 = 1, V542 = 2, V543 = 3, V545 = 5, V548 = 8, V549 = 9, V545LP = 15, V546LP = 16};enum address_mode{ c_mode, /* 16-bit addresses. */ far_mode /* >16-bit addresses. */};#define OPTION_ADDRESS_MODE (OPTION_MD_BASE)#define OPTION_CPU_VERSION (OPTION_ADDRESS_MODE + 1)#define OPTION_COFF_VERSION (OPTION_CPU_VERSION + 1)#define OPTION_STDERR_TO_FILE (OPTION_COFF_VERSION + 1)struct option md_longopts[] ={ { "mfar-mode", no_argument, NULL, OPTION_ADDRESS_MODE }, { "mf", no_argument, NULL, OPTION_ADDRESS_MODE }, { "mcpu", required_argument, NULL, OPTION_CPU_VERSION },#if 0 { "mcoff-version", required_argument, NULL, OPTION_COFF_VERSION },#endif { "merrors-to-file", required_argument, NULL, OPTION_STDERR_TO_FILE }, { "me", required_argument, NULL, OPTION_STDERR_TO_FILE }, { NULL, no_argument, NULL, 0},};size_t md_longopts_size = sizeof (md_longopts);static int assembly_begun = 0;/* Addressing mode is not entirely implemented; the latest rev of the Other assembler doesn't seem to make any distinction whatsoever; all relocations are stored as extended relocatiosn. Older versions used REL16 vs RELEXT16, but now it seems all relocations are RELEXT16. We use all RELEXT16. The cpu version is kind of a waste of time as well. There is one instruction (RND) for LP devices only, and several for devices with extended addressing only. We include it for compatibility. */static enum address_mode amode = c_mode;static enum cpu_version cpu = VNONE;/* Include string substitutions in listing? */static int listing_sslist = 0;/* Did we do subsym substitutions on the line? */static int substitution_line = 0;/* Last label seen. */static symbolS *last_label_seen = NULL;/* This ensures that all new labels are unique. */static int local_label_id;static struct hash_control *subsym_recurse_hash; /* Prevent infinite recurse. */static struct hash_control *math_hash; /* Built-in math functions. *//* Allow maximum levels of macro nesting; level 0 is the main substitution symbol table. The other assembler only does 32 levels, so there! */static struct hash_control *subsym_hash[100];/* Keep track of local labels so we can substitute them before GAS sees them since macros use their own 'namespace' for local labels, use a separate hash We do our own local label handling 'cuz it's subtly different from the stock GAS handling. We use our own macro nesting counter, since GAS overloads it when expanding other things (like conditionals and repeat loops). */static int macro_level = 0;static struct hash_control *local_label_hash[100];/* Keep track of struct/union tags. */static struct hash_control *stag_hash;static struct hash_control *op_hash;static struct hash_control *parop_hash;static struct hash_control *reg_hash;static struct hash_control *mmreg_hash;static struct hash_control *cc_hash;static struct hash_control *cc2_hash;static struct hash_control *cc3_hash;static struct hash_control *sbit_hash;static struct hash_control *misc_symbol_hash;static char *subsym_substitute PARAMS ((char *line, int forced));static char *subsym_lookup PARAMS ((char *name, int nest_level));static void subsym_create_or_replace PARAMS ((char *name, char *value));static float math_ceil PARAMS ((float, float));static float math_cvi PARAMS ((float, float));static float math_floor PARAMS ((float, float));static float math_fmod PARAMS ((float, float));static float math_int PARAMS ((float, float));static float math_round PARAMS ((float, float));static float math_sgn PARAMS ((float, float));static float math_trunc PARAMS ((float, float));static float math_acos PARAMS ((float, float));static float math_asin PARAMS ((float, float));static float math_atan PARAMS ((float, float));static float math_atan2 PARAMS ((float, float));static float math_cosh PARAMS ((float, float));static float math_cos PARAMS ((float, float));static float math_cvf PARAMS ((float, float));static float math_exp PARAMS ((float, float));static float math_fabs PARAMS ((float, float));static float math_ldexp PARAMS ((float, float));static float math_log10 PARAMS ((float, float));static float math_log PARAMS ((float, float));static float math_max PARAMS ((float, float));static float math_pow PARAMS ((float, float));static float math_sin PARAMS ((float, float));static float math_sinh PARAMS ((float, float));static float math_sqrt PARAMS ((float, float));static float math_tan PARAMS ((float, float));static float math_tanh PARAMS ((float, float));static struct stag{ symbolS *sym; /* Symbol for this stag; value is offset. */ const char *name; /* Shortcut to symbol name. */ bfd_vma size; /* Size of struct/union. */ int current_bitfield_offset; /* Temporary for tracking fields. */ int is_union; struct stag_field /* List of fields. */ { const char *name; bfd_vma offset; /* Of start of this field. */ int bitfield_offset; /* Of start of this field. */ struct stag *stag; /* If field is struct/union. */ struct stag_field *next; } *field; /* For nesting; used only in stag construction. */ struct stag *inner; /* Enclosed .struct. */ struct stag *outer; /* Enclosing .struct. */} *current_stag = NULL;static segT stag_saved_seg;static subsegT stag_saved_subseg;/* Output a single character (upper octect is zero). */static voidtic54x_emit_char (c) char c;{ expressionS exp; exp.X_op = O_constant; exp.X_add_number = c; emit_expr (&exp, 2);}/* Walk backwards in the frag chain. */static fragS *frag_prev (frag, seg) fragS *frag; segT seg;{ segment_info_type *seginfo = seg_info (seg); fragS *fragp; for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next) if (fragp->fr_next == frag) return fragp; return NULL;}static fragS *bit_offset_frag (frag, seg) fragS *frag; segT seg;{ while (frag != NULL) { if (frag->fr_fix == 0 && frag->fr_opcode == NULL && frag->tc_frag_data == 0) frag = frag_prev (frag, seg); else return frag; } return NULL;}/* Return the number of bits allocated in the most recent word, or zero if none. .field/.space/.bes may leave words partially allocated. */static intfrag_bit_offset (frag, seg) fragS *frag; segT seg;{ frag = bit_offset_frag (frag, seg); if (frag) return frag->fr_opcode != NULL ? -1 : frag->tc_frag_data; return 0;}/* Read an expression from a C string; returns a pointer past the end of the expression. */static char *parse_expression (char *str, expressionS * exp){ char *s; char *tmp; tmp = input_line_pointer; /* Save line pointer. */ input_line_pointer = str; expression (exp); s = input_line_pointer; input_line_pointer = tmp; /* Restore line pointer. */ return s; /* Return pointer to where parsing stopped. */}/* .asg "character-string"|character-string, symbol .eval is the only pseudo-op allowed to perform arithmetic on substitution symbols. all other use of symbols defined with .asg are currently unsupported. */static voidtic54x_asg (x) int x ATTRIBUTE_UNUSED;{ int c; char *name; char *str; char *tmp; int quoted = *input_line_pointer == '"'; ILLEGAL_WITHIN_STRUCT (); if (quoted) { int len; str = demand_copy_C_string (&len); c = *input_line_pointer; } else { str = input_line_pointer; while ((c = *input_line_pointer) != ',') { if (is_end_of_line[(int) *input_line_pointer]) break; ++input_line_pointer; } *input_line_pointer = 0; } if (c != ',') { as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'")); ignore_rest_of_line (); return; } name = ++input_line_pointer; c = get_symbol_end (); /* Get terminator. */ if (!isalpha (*name)) { as_bad ("symbols assigned with .asg must begin with a letter"); ignore_rest_of_line (); return; } tmp = xmalloc (strlen (str) + 1); strcpy (tmp, str); str = tmp; tmp = xmalloc (strlen (name) + 1); strcpy (tmp, name); name = tmp; subsym_create_or_replace (name, str); *input_line_pointer = c; demand_empty_rest_of_line ();}/* .eval expression, symbol There's something screwy about this. The other assembler sometimes does and sometimes doesn't substitute symbols defined with .eval. We'll put the symbols into the subsym table as well as the normal symbol table, since that's what works best. */static voidtic54x_eval (x) int x ATTRIBUTE_UNUSED;{ char c; int value; char *name; symbolS *symbolP; char valuestr[32], *tmp; int quoted; ILLEGAL_WITHIN_STRUCT (); SKIP_WHITESPACE (); quoted = *input_line_pointer == '"'; if (quoted) ++input_line_pointer; value = get_absolute_expression (); if (quoted) { if (*input_line_pointer != '"') { as_bad (_("Unterminated string after absolute expression")); ignore_rest_of_line (); return; } ++input_line_pointer; } if (*input_line_pointer++ != ',') { as_bad (_("Comma and symbol expected for '.eval EXPR, SYMBOL'")); ignore_rest_of_line (); return; } name = input_line_pointer; c = get_symbol_end (); /* Get terminator. */ tmp = xmalloc (strlen (name) + 1); name = strcpy (tmp, name); *input_line_pointer = c; if (!isalpha (*name)) { as_bad (_("symbols assigned with .eval must begin with a letter")); ignore_rest_of_line (); return; } symbolP = symbol_new (name, absolute_section, (valueT) value, &zero_address_frag); SF_SET_LOCAL (symbolP); symbol_table_insert (symbolP); /* The "other" assembler sometimes doesn't put .eval's in the subsym table But since there's not written rule as to when, don't even bother trying to match their behavior. */ sprintf (valuestr, "%d", value); tmp = xmalloc (strlen (valuestr) + 1); strcpy (tmp, valuestr); subsym_create_or_replace (name, tmp); demand_empty_rest_of_line ();}/* .bss symbol, size [, [blocking flag] [, alignment flag] alignment is to a longword boundary; blocking is to 128-word boundary. 1) if there is a hole in memory, this directive should attempt to fill it (not yet implemented). 2) if the blocking flag is not set, allocate at the current SPC otherwise, check to see if the current SPC plus the space to be allocated crosses the page boundary (128 words). if there's not enough space, create a hole and align with the next page boundary. (not yet implemented). */static voidtic54x_bss (x) int x ATTRIBUTE_UNUSED;{ char c; char *name; char *p; int words; segT current_seg; subsegT current_subseg; symbolS *symbolP; int block = 0; int align = 0; ILLEGAL_WITHIN_STRUCT (); current_seg = now_seg; /* Save current seg. */ current_subseg = now_subseg; /* Save current subseg. */ name = input_line_pointer; c = get_symbol_end (); /* Get terminator. */ if (c != ',') { as_bad (".bss size argument missing\n"); ignore_rest_of_line (); return; } ++input_line_pointer; words = get_absolute_expression (); if (words < 0) { as_bad (".bss size %d < 0!", words); ignore_rest_of_line (); return; } if (*input_line_pointer == ',')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -