📄 tc-d10v.c
字号:
/* tc-d10v.c -- Assembler code for the Mitsubishi D10V Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 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. */#include <stdio.h>#include <ctype.h>#include "as.h"#include "subsegs.h"#include "opcode/d10v.h"#include "elf/ppc.h"//#include "read.h"const char comment_chars[] = ";";const char line_comment_chars[] = "#";const char line_separator_chars[] = "";const char *md_shortopts = "O";const char EXP_CHARS[] = "eE";const char FLT_CHARS[] = "dD";int Optimizing = 0;#define AT_WORD_P(X) ((X)->X_op == O_right_shift \ && (X)->X_op_symbol != NULL \ && symbol_constant_p ((X)->X_op_symbol) \ && S_GET_VALUE ((X)->X_op_symbol) == AT_WORD_RIGHT_SHIFT)#define AT_WORD_RIGHT_SHIFT 2/* Fixups. */#define MAX_INSN_FIXUPS (5)struct d10v_fixup{ expressionS exp; int operand; int pcrel; int size; bfd_reloc_code_real_type reloc;};typedef struct _fixups{ int fc; struct d10v_fixup fix[MAX_INSN_FIXUPS]; struct _fixups *next;} Fixups;static Fixups FixUps[2];static Fixups *fixups;static int do_not_ignore_hash = 0;typedef int packing_type;#define PACK_UNSPEC (0) /* Packing order not specified. */#define PACK_PARALLEL (1) /* "||" */#define PACK_LEFT_RIGHT (2) /* "->" */#define PACK_RIGHT_LEFT (3) /* "<-" */static packing_type etype = PACK_UNSPEC; /* Used by d10v_cleanup. *//* True if instruction swapping warnings should be inhibited. --nowarnswap. */static boolean flag_warn_suppress_instructionswap;/* True if instruction packing should be performed when --gstabs is specified. --gstabs-packing, --no-gstabs-packing. */static boolean flag_allow_gstabs_packing = 1;/* Local functions. */static int reg_name_search PARAMS ((char *name));static int register_name PARAMS ((expressionS *expressionP));static int check_range PARAMS ((unsigned long num, int bits, int flags));static int postfix PARAMS ((char *p));static bfd_reloc_code_real_type get_reloc PARAMS ((struct d10v_operand *op));static int get_operands PARAMS ((expressionS exp[]));static struct d10v_opcode *find_opcode PARAMS ((struct d10v_opcode *opcode, expressionS ops[]));static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS *opers, unsigned long insn));static void write_long PARAMS ((unsigned long insn, Fixups *fx));static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1, struct d10v_opcode *opcode2, unsigned long insn2, packing_type exec_type, Fixups *fx));static unsigned long do_assemble PARAMS ((char *str, struct d10v_opcode **opcode));static unsigned long d10v_insert_operand PARAMS (( unsigned long insn, int op_type, offsetT value, int left, fixS *fix));static int parallel_ok PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1, struct d10v_opcode *opcode2, unsigned long insn2, packing_type exec_type));static symbolS * find_symbol_matching_register PARAMS ((expressionS *));struct option md_longopts[] ={#define OPTION_NOWARNSWAP (OPTION_MD_BASE) {"nowarnswap", no_argument, NULL, OPTION_NOWARNSWAP},#define OPTION_GSTABSPACKING (OPTION_MD_BASE + 1) {"gstabspacking", no_argument, NULL, OPTION_GSTABSPACKING}, {"gstabs-packing", no_argument, NULL, OPTION_GSTABSPACKING},#define OPTION_NOGSTABSPACKING (OPTION_MD_BASE + 2) {"nogstabspacking", no_argument, NULL, OPTION_NOGSTABSPACKING}, {"no-gstabs-packing", no_argument, NULL, OPTION_NOGSTABSPACKING}, {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);static void d10v_dot_word PARAMS ((int));/* The target specific pseudo-ops which we support. */const pseudo_typeS md_pseudo_table[] ={ { "word", d10v_dot_word, 2 }, { NULL, NULL, 0 }};/* Opcode hash table. */static struct hash_control *d10v_hash;/* Do a binary search of the d10v_predefined_registers array to see if NAME is a valid regiter name. Return the register number from the array on success, or -1 on failure. */static intreg_name_search (name) char *name;{ int middle, low, high; int cmp; low = 0; high = d10v_reg_name_cnt () - 1; do { middle = (low + high) / 2; cmp = strcasecmp (name, d10v_predefined_registers[middle].name); if (cmp < 0) high = middle - 1; else if (cmp > 0) low = middle + 1; else return d10v_predefined_registers[middle].value; } while (low <= high); return -1;}/* Check the string at input_line_pointer to see if it is a valid register name. */static intregister_name (expressionP) expressionS *expressionP;{ int reg_number; char c, *p = input_line_pointer; while (*p && *p != '\n' && *p != '\r' && *p != ',' && *p != ' ' && *p != ')') p++; c = *p; if (c) *p++ = 0; /* Look to see if it's in the register table. */ reg_number = reg_name_search (input_line_pointer); if (reg_number >= 0) { expressionP->X_op = O_register; /* Temporarily store a pointer to the string here. */ expressionP->X_op_symbol = (symbolS *) input_line_pointer; expressionP->X_add_number = reg_number; input_line_pointer = p; return 1; } if (c) *(p - 1) = c; return 0;}static intcheck_range (num, bits, flags) unsigned long num; int bits; int flags;{ long min, max; int retval = 0; /* Don't bother checking 16-bit values. */ if (bits == 16) return 0; if (flags & OPERAND_SHIFT) { /* All special shift operands are unsigned and <= 16. We allow 0 for now. */ if (num > 16) return 1; else return 0; } if (flags & OPERAND_SIGNED) { /* Signed 3-bit integers are restricted to the (-2, 3) range. */ if (flags & RESTRICTED_NUM3) { if ((long) num < -2 || (long) num > 3) retval = 1; } else { max = (1 << (bits - 1)) - 1; min = - (1 << (bits - 1)); if (((long) num > max) || ((long) num < min)) retval = 1; } } else { max = (1 << bits) - 1; min = 0; if (((long) num > max) || ((long) num < min)) retval = 1; } return retval;}voidmd_show_usage (stream) FILE *stream;{ fprintf (stream, _("D10V options:\n\-O Optimize. Will do some operations in parallel.\n\--gstabs-packing Pack adjacent short instructions together even\n\ when --gstabs is specified. On by default.\n\--no-gstabs-packing If --gstabs is specified, do not pack adjacent\n\ instructions together.\n"));}intmd_parse_option (c, arg) int c; char *arg ATTRIBUTE_UNUSED;{ switch (c) { case 'O': /* Optimize. Will attempt to parallelize operations. */ Optimizing = 1; break; case OPTION_NOWARNSWAP: flag_warn_suppress_instructionswap = 1; break; case OPTION_GSTABSPACKING: flag_allow_gstabs_packing = 1; break; case OPTION_NOGSTABSPACKING: flag_allow_gstabs_packing = 0; break; default: return 0; } return 1;}symbolS *md_undefined_symbol (name) char *name ATTRIBUTE_UNUSED;{ return 0;}/* Turn a string in input_line_pointer into a floating point constant of type TYPE, and store the appropriate bytes in *LITP. The number of LITTLENUMS emitted is stored in *SIZEP. An error message is returned, or NULL on OK. */char *md_atof (type, litP, sizeP) int type; char *litP; int *sizeP;{ int prec; LITTLENUM_TYPE words[4]; char *t; int i; switch (type) { case 'f': prec = 2; break; case 'd': prec = 4; break; default: *sizeP = 0; return _("bad call to md_atof"); } t = atof_ieee (input_line_pointer, type, words); if (t) input_line_pointer = t; *sizeP = prec * 2; for (i = 0; i < prec; i++) { md_number_to_chars (litP, (valueT) words[i], 2); litP += 2; } return NULL;}voidmd_convert_frag (abfd, sec, fragP) bfd *abfd ATTRIBUTE_UNUSED; asection *sec ATTRIBUTE_UNUSED; fragS *fragP ATTRIBUTE_UNUSED;{ abort ();}valueTmd_section_align (seg, addr) asection *seg; valueT addr;{ int align = bfd_get_section_alignment (stdoutput, seg); return ((addr + (1 << align) - 1) & (-1 << align));}voidmd_begin (){ char *prev_name = ""; struct d10v_opcode *opcode; d10v_hash = hash_new (); /* Insert unique names into hash table. The D10v instruction set has many identical opcode names that have different opcodes based on the operands. This hash table then provides a quick index to the first opcode with a particular name in the opcode table. */ for (opcode = (struct d10v_opcode *) d10v_opcodes; opcode->name; opcode++) { if (strcmp (prev_name, opcode->name)) { prev_name = (char *) opcode->name; hash_insert (d10v_hash, opcode->name, (char *) opcode); } } fixups = &FixUps[0]; FixUps[0].next = &FixUps[1]; FixUps[1].next = &FixUps[0];}/* Remove the postincrement or postdecrement operator ( '+' or '-' ) from an expression. */static intpostfix (p) char *p;{ while (*p != '-' && *p != '+') { if (*p == 0 || *p == '\n' || *p == '\r') break; p++; } if (*p == '-') { *p = ' '; return (-1); } if (*p == '+') { *p = ' '; return (1); } return (0);}static bfd_reloc_code_real_typeget_reloc (op) struct d10v_operand *op;{ int bits = op->bits; if (bits <= 4) return (0); if (op->flags & OPERAND_ADDR) { if (bits == 8) return (BFD_RELOC_D10V_10_PCREL_R); else return (BFD_RELOC_D10V_18_PCREL); } return (BFD_RELOC_16);}/* Parse a string of operands. Return an array of expressions. */static intget_operands (exp) expressionS exp[];{ char *p = input_line_pointer; int numops = 0; int post = 0; int uses_at = 0; while (*p) { while (*p == ' ' || *p == '\t' || *p == ',') p++; if (*p == 0 || *p == '\n' || *p == '\r') break; if (*p == '@') { uses_at = 1; p++; exp[numops].X_op = O_absent; if (*p == '(') { p++; exp[numops].X_add_number = OPERAND_ATPAR; } else if (*p == '-') { p++; exp[numops].X_add_number = OPERAND_ATMINUS; } else { exp[numops].X_add_number = OPERAND_ATSIGN; post = postfix (p); } numops++; continue; } if (*p == ')') { /* Just skip the trailing paren. */ p++; continue; } input_line_pointer = p; /* Check to see if it might be a register name. */ if (!register_name (&exp[numops])) { /* Parse as an expression. */ if (uses_at) { /* Any expression that involves the indirect addressing cannot also involve immediate addressing. Therefore the use of the hash character is illegal. */ int save = do_not_ignore_hash; do_not_ignore_hash = 1; expression (&exp[numops]); do_not_ignore_hash = save; } else expression (&exp[numops]); } if (strncasecmp (input_line_pointer, "@word", 5) == 0) { input_line_pointer += 5; if (exp[numops].X_op == O_register) { /* If it looked like a register name but was followed by "@word" then it was really a symbol, so change it to one. */ exp[numops].X_op = O_symbol; exp[numops].X_add_symbol = symbol_find_or_make ((char *) exp[numops].X_op_symbol); } /* Check for identifier@word+constant. */ if (*input_line_pointer == '-' || *input_line_pointer == '+') { expressionS new_exp; expression (&new_exp); exp[numops].X_add_number = new_exp.X_add_number; } /* Convert expr into a right shift by AT_WORD_RIGHT_SHIFT. */ { expressionS new_exp; memset (&new_exp, 0, sizeof new_exp); new_exp.X_add_number = AT_WORD_RIGHT_SHIFT; new_exp.X_op = O_constant; new_exp.X_unsigned = 1; exp[numops].X_op_symbol = make_expr_symbol (&new_exp); exp[numops].X_op = O_right_shift; } know (AT_WORD_P (&exp[numops])); } if (exp[numops].X_op == O_illegal) as_bad (_("illegal operand")); else if (exp[numops].X_op == O_absent) as_bad (_("missing operand")); numops++; p = input_line_pointer; } switch (post) { case -1: /* Postdecrement mode. */ exp[numops].X_op = O_absent; exp[numops++].X_add_number = OPERAND_MINUS; break; case 1: /* Postincrement mode. */ exp[numops].X_op = O_absent; exp[numops++].X_add_number = OPERAND_PLUS; break; } exp[numops].X_op = 0; return (numops);}static unsigned longd10v_insert_operand (insn, op_type, value, left, fix) unsigned long insn; int op_type; offsetT value; int left; fixS *fix;{ int shift, bits; shift = d10v_operands[op_type].shift; if (left) shift += 15; bits = d10v_operands[op_type].bits; /* Truncate to the proper number of bits. */ if (check_range (value, bits, d10v_operands[op_type].flags)) as_bad_where (fix->fx_file, fix->fx_line, _("operand out of range: %d"), value); value &= 0x7FFFFFFF >> (31 - bits); insn |= (value << shift); return insn;}/* Take a pointer to the opcode entry in the opcode table and the array of operand expressions. Return the instruction. */static unsigned longbuild_insn (opcode, opers, insn) struct d10v_opcode *opcode; expressionS *opers; unsigned long insn;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -