📄 tc-tic30.c
字号:
/* tc-c30.c -- Assembly code for the Texas Instruments TMS320C30 Copyright 1998, 1999, 2000 Free Software Foundation, Inc. Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au) 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 TMS320C30 machine specific gas. Written by Steven Haworth (steve@pm.cse.rmit.edu.au). Bugs & suggestions are completely welcome. This is free software. Please help us make it better. */#include "as.h"#include "opcode/tic30.h"/* Put here all non-digit non-letter charcters that may occur in an operand. */static char operand_special_chars[] = "%$-+(,)*._~/<>&^!:[@]";static char *ordinal_names[] = { "first", "second", "third", "fourth", "fifth"};const int md_reloc_size = 0;const char comment_chars[] = ";";const char line_comment_chars[] = "*";const char line_separator_chars[] = "";const char *md_shortopts = "";struct option md_longopts[] = { {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);/* Chars that mean this number is a floating point constant. *//* As in 0f12.456 *//* or 0d1.2345e12 */const char FLT_CHARS[] = "fFdDxX";/* Chars that can be used to separate mant from exp in floating point nums. */const char EXP_CHARS[] = "eE";/* tables for lexical analysis */static char opcode_chars[256];static char register_chars[256];static char operand_chars[256];static char space_chars[256];static char identifier_chars[256];static char digit_chars[256];/* lexical macros */#define is_opcode_char(x) (opcode_chars[(unsigned char) x])#define is_operand_char(x) (operand_chars[(unsigned char) x])#define is_register_char(x) (register_chars[(unsigned char) x])#define is_space_char(x) (space_chars[(unsigned char) x])#define is_identifier_char(x) (identifier_chars[(unsigned char) x])#define is_digit_char(x) (digit_chars[(unsigned char) x])const pseudo_typeS md_pseudo_table[] = { {0, 0, 0}};#undef USE_STDOUT#define USE_STDOUT 1#ifdef USE_STDARG#include <stdarg.h>intdebug (const char *string, ...){ if (flag_debug) { va_list argptr; char str[100]; va_start (argptr, string); vsprintf (str, string, argptr); if (str[0] == '\0') return (0); va_end (argptr); fputs (str, USE_STDOUT ? stdout : stderr); return strlen (str); } else return 0;}#elseintdebug (string, va_alist) const char *string; va_dcl{ if (flag_debug) { va_list argptr; char str[100]; int cnt; va_start (argptr, string); cnt = vsprintf (str, string, argptr); if (str[0] == NULL) return (0); va_end (argptr); fputs (str, USE_STDOUT ? stdout : stderr); return (cnt); } else return 0;}#endif/* hash table for opcode lookup */static struct hash_control *op_hash;/* hash table for parallel opcode lookup */static struct hash_control *parop_hash;/* hash table for register lookup */static struct hash_control *reg_hash;/* hash table for indirect addressing lookup */static struct hash_control *ind_hash;voidmd_begin (){ const char *hash_err; debug ("In md_begin()\n"); op_hash = hash_new (); { const template *current_optab = tic30_optab; for (; current_optab < tic30_optab_end; current_optab++) { hash_err = hash_insert (op_hash, current_optab->name, (char *) current_optab); if (hash_err) as_fatal ("Internal Error: Can't Hash %s: %s", current_optab->name, hash_err); } } parop_hash = hash_new (); { const partemplate *current_parop = tic30_paroptab; for (; current_parop < tic30_paroptab_end; current_parop++) { hash_err = hash_insert (parop_hash, current_parop->name, (char *) current_parop); if (hash_err) as_fatal ("Internal Error: Can't Hash %s: %s", current_parop->name, hash_err); } } reg_hash = hash_new (); { const reg *current_reg = tic30_regtab; for (; current_reg < tic30_regtab_end; current_reg++) { hash_err = hash_insert (reg_hash, current_reg->name, (char *) current_reg); if (hash_err) as_fatal ("Internal Error: Can't Hash %s: %s", current_reg->name, hash_err); } } ind_hash = hash_new (); { const ind_addr_type *current_ind = tic30_indaddr_tab; for (; current_ind < tic30_indaddrtab_end; current_ind++) { hash_err = hash_insert (ind_hash, current_ind->syntax, (char *) current_ind); if (hash_err) as_fatal ("Internal Error: Can't Hash %s: %s", current_ind->syntax, hash_err); } } /* fill in lexical tables: opcode_chars, operand_chars, space_chars */ { register int c; register char *p; for (c = 0; c < 256; c++) { if (islower (c) || isdigit (c)) { opcode_chars[c] = c; register_chars[c] = c; } else if (isupper (c)) { opcode_chars[c] = tolower (c); register_chars[c] = opcode_chars[c]; } else if (c == ')' || c == '(') { register_chars[c] = c; } if (isupper (c) || islower (c) || isdigit (c)) operand_chars[c] = c; if (isdigit (c) || c == '-') digit_chars[c] = c; if (isalpha (c) || c == '_' || c == '.' || isdigit (c)) identifier_chars[c] = c; if (c == ' ' || c == '\t') space_chars[c] = c; if (c == '_') opcode_chars[c] = c; } for (p = operand_special_chars; *p != '\0'; p++) operand_chars[(unsigned char) *p] = *p; }}/* Address Mode OR values */#define AM_Register 0x00000000#define AM_Direct 0x00200000#define AM_Indirect 0x00400000#define AM_Immediate 0x00600000#define AM_NotReq 0xFFFFFFFF/* PC Relative OR values */#define PC_Register 0x00000000#define PC_Relative 0x02000000typedef struct { unsigned op_type; struct { int resolved; unsigned address; char *label; expressionS direct_expr; } direct; struct { unsigned mod; int ARnum; unsigned char disp; } indirect; struct { unsigned opcode; } reg; struct { int resolved; int decimal_found; float f_number; int s_number; unsigned int u_number; char *label; expressionS imm_expr; } immediate;} operand;int tic30_parallel_insn PARAMS ((char *));operand *tic30_operand PARAMS ((char *));char *tic30_find_parallel_insn PARAMS ((char *, char *));template *opcode;struct tic30_insn { template *tm; /* Template of current instruction */ unsigned opcode; /* Final opcode */ int operands; /* Number of given operands */ /* Type of operand given in instruction */ operand *operand_type[MAX_OPERANDS]; unsigned addressing_mode; /* Final addressing mode of instruction */};struct tic30_insn insn;static int found_parallel_insn;voidmd_assemble (line) char *line;{ template *opcode; char *current_posn; char *token_start; char save_char; int count; debug ("In md_assemble() with argument %s\n", line); memset (&insn, '\0', sizeof (insn)); if (found_parallel_insn) { debug ("Line is second part of parallel instruction\n\n"); found_parallel_insn = 0; return; } if ((current_posn = tic30_find_parallel_insn (line, input_line_pointer + 1)) == NULL) current_posn = line; else found_parallel_insn = 1; while (is_space_char (*current_posn)) current_posn++; token_start = current_posn; if (!is_opcode_char (*current_posn)) { as_bad ("Invalid character %s in opcode", output_invalid (*current_posn)); return; } /* Check if instruction is a parallel instruction by seeing if the first character is a q. */ if (*token_start == 'q') { if (tic30_parallel_insn (token_start)) { if (found_parallel_insn) free (token_start); return; } } while (is_opcode_char (*current_posn)) current_posn++; { /* Find instruction */ save_char = *current_posn; *current_posn = '\0'; opcode = (template *) hash_find (op_hash, token_start); if (opcode) { debug ("Found instruction %s\n", opcode->name); insn.tm = opcode; } else { debug ("Didn't find insn\n"); as_bad ("Unknown TMS320C30 instruction: %s", token_start); return; } *current_posn = save_char; } if (*current_posn != END_OF_INSN) { /* Find operands */ int paren_not_balanced; int expecting_operand = 0; int this_operand; do { /* skip optional white space before operand */ while (!is_operand_char (*current_posn) && *current_posn != END_OF_INSN) { if (!is_space_char (*current_posn)) { as_bad ("Invalid character %s before %s operand", output_invalid (*current_posn), ordinal_names[insn.operands]); return; } current_posn++; } token_start = current_posn; /* after white space */ paren_not_balanced = 0; while (paren_not_balanced || *current_posn != ',') { if (*current_posn == END_OF_INSN) { if (paren_not_balanced) { as_bad ("Unbalanced parenthesis in %s operand.", ordinal_names[insn.operands]); return; } else break; /* we are done */ } else if (!is_operand_char (*current_posn) && !is_space_char (*current_posn)) { as_bad ("Invalid character %s in %s operand", output_invalid (*current_posn), ordinal_names[insn.operands]); return; } if (*current_posn == '(') ++paren_not_balanced; if (*current_posn == ')') --paren_not_balanced; current_posn++; } if (current_posn != token_start) { /* yes, we've read in another operand */ this_operand = insn.operands++; if (insn.operands > MAX_OPERANDS) { as_bad ("Spurious operands; (%d operands/instruction max)", MAX_OPERANDS); return; } /* now parse operand adding info to 'insn' as we go along */ save_char = *current_posn; *current_posn = '\0'; insn.operand_type[this_operand] = tic30_operand (token_start); *current_posn = save_char; if (insn.operand_type[this_operand] == NULL) return; } else { if (expecting_operand) { as_bad ("Expecting operand after ','; got nothing"); return; } if (*current_posn == ',') { as_bad ("Expecting operand before ','; got nothing"); return; } } /* now *current_posn must be either ',' or END_OF_INSN */ if (*current_posn == ',') { if (*++current_posn == END_OF_INSN) { /* just skip it, if it's \n complain */ as_bad ("Expecting operand after ','; got nothing"); return; } expecting_operand = 1; } } while (*current_posn != END_OF_INSN); /* until we get end of insn */ } debug ("Number of operands found: %d\n", insn.operands); /* Check that number of operands is correct */ if (insn.operands != insn.tm->operands) { int i; int numops = insn.tm->operands; /* If operands are not the same, then see if any of the operands are not required. Then recheck with number of given operands. If they are still not the same, then give an error, otherwise carry on. */ for (i = 0; i < insn.tm->operands; i++) if (insn.tm->operand_types[i] & NotReq) numops--; if (insn.operands != numops) { as_bad ("Incorrect number of operands given"); return; } } insn.addressing_mode = AM_NotReq; for (count = 0; count < insn.operands; count++) { if (insn.operand_type[count]->op_type & insn.tm->operand_types[count]) { debug ("Operand %d matches\n", count + 1); /* If instruction has two operands and has an AddressMode modifier then set addressing mode type for instruction */ if (insn.tm->opcode_modifier == AddressMode) { int addr_insn = 0; /* Store instruction uses the second operand for the address mode. */ if ((insn.tm->operand_types[1] & (Indirect | Direct)) == (Indirect | Direct)) addr_insn = 1; if (insn.operand_type[addr_insn]->op_type & (AllReg)) insn.addressing_mode = AM_Register; else if (insn.operand_type[addr_insn]->op_type & Direct) insn.addressing_mode = AM_Direct; else if (insn.operand_type[addr_insn]->op_type & Indirect) insn.addressing_mode = AM_Indirect; else insn.addressing_mode = AM_Immediate; } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -