📄 tc-mn10300.c
字号:
/* tc-mn10300.c -- Assembler code for the Matsushita 10300 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/mn10300.h"#include "dwarf2dbg.h"/* Structure to hold information about predefined registers. */struct reg_name{ const char *name; int value;};/* Generic assembler global variables which must be defined by all targets. *//* Characters which always start a comment. */const char comment_chars[] = "#";/* Characters which start a comment at the beginning of a line. */const char line_comment_chars[] = ";#";/* Characters which may be used to separate multiple commands on a single line. */const char line_separator_chars[] = ";";/* Characters which are used to indicate an exponent in a floating point number. */const char EXP_CHARS[] = "eE";/* Characters which mean that a number is a floating point constant, as in 0d1.0. */const char FLT_CHARS[] = "dD";const relax_typeS md_relax_table[] = { /* bCC relaxing */ {0x7f, -0x80, 2, 1}, {0x7fff, -0x8000, 5, 2}, {0x7fffffff, -0x80000000, 7, 0}, /* bCC relaxing (uncommon cases) */ {0x7f, -0x80, 3, 4}, {0x7fff, -0x8000, 6, 5}, {0x7fffffff, -0x80000000, 8, 0}, /* call relaxing */ {0x7fff, -0x8000, 5, 7}, {0x7fffffff, -0x80000000, 7, 0}, /* calls relaxing */ {0x7fff, -0x8000, 4, 9}, {0x7fffffff, -0x80000000, 6, 0}, /* jmp relaxing */ {0x7f, -0x80, 2, 11}, {0x7fff, -0x8000, 3, 12}, {0x7fffffff, -0x80000000, 5, 0},};/* Local functions. */static void mn10300_insert_operand PARAMS ((unsigned long *, unsigned long *, const struct mn10300_operand *, offsetT, char *, unsigned, unsigned));static unsigned long check_operand PARAMS ((unsigned long, const struct mn10300_operand *, offsetT));static int reg_name_search PARAMS ((const struct reg_name *, int, const char *));static boolean data_register_name PARAMS ((expressionS *expressionP));static boolean address_register_name PARAMS ((expressionS *expressionP));static boolean other_register_name PARAMS ((expressionS *expressionP));static void set_arch_mach PARAMS ((int));/* Set linkrelax here to avoid fixups in most sections. */int linkrelax = 1;static int current_machine;/* Fixups. */#define MAX_INSN_FIXUPS (5)struct mn10300_fixup{ expressionS exp; int opindex; bfd_reloc_code_real_type reloc;};struct mn10300_fixup fixups[MAX_INSN_FIXUPS];static int fc;/* We must store the value of each register operand so that we can verify that certain registers do not match. */int mn10300_reg_operands[MN10300_MAX_OPERANDS];const char *md_shortopts = "";struct option md_longopts[] = { {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);/* The target specific pseudo-ops which we support. */const pseudo_typeS md_pseudo_table[] ={ { "file", dwarf2_directive_file, 0 }, { "loc", dwarf2_directive_loc, 0 }, { "am30", set_arch_mach, AM30 }, { "am33", set_arch_mach, AM33 }, { "mn10300", set_arch_mach, MN103 }, {NULL, 0, 0}};#define HAVE_AM33 (current_machine == AM33)#define HAVE_AM30 (current_machine == AM30)/* Opcode hash table. */static struct hash_control *mn10300_hash;/* This table is sorted. Suitable for searching by a binary search. */static const struct reg_name data_registers[] ={ { "d0", 0 }, { "d1", 1 }, { "d2", 2 }, { "d3", 3 },};#define DATA_REG_NAME_CNT \ (sizeof (data_registers) / sizeof (struct reg_name))static const struct reg_name address_registers[] ={ { "a0", 0 }, { "a1", 1 }, { "a2", 2 }, { "a3", 3 },};#define ADDRESS_REG_NAME_CNT \ (sizeof (address_registers) / sizeof (struct reg_name))static const struct reg_name r_registers[] ={ { "a0", 8 }, { "a1", 9 }, { "a2", 10 }, { "a3", 11 }, { "d0", 12 }, { "d1", 13 }, { "d2", 14 }, { "d3", 15 }, { "e0", 0 }, { "e1", 1 }, { "e10", 10 }, { "e11", 11 }, { "e12", 12 }, { "e13", 13 }, { "e14", 14 }, { "e15", 15 }, { "e2", 2 }, { "e3", 3 }, { "e4", 4 }, { "e5", 5 }, { "e6", 6 }, { "e7", 7 }, { "e8", 8 }, { "e9", 9 }, { "r0", 0 }, { "r1", 1 }, { "r10", 10 }, { "r11", 11 }, { "r12", 12 }, { "r13", 13 }, { "r14", 14 }, { "r15", 15 }, { "r2", 2 }, { "r3", 3 }, { "r4", 4 }, { "r5", 5 }, { "r6", 6 }, { "r7", 7 }, { "r8", 8 }, { "r9", 9 },};#define R_REG_NAME_CNT \ (sizeof (r_registers) / sizeof (struct reg_name))static const struct reg_name xr_registers[] ={ { "mcrh", 2 }, { "mcrl", 3 }, { "mcvf", 4 }, { "mdrq", 1 }, { "pc", 0 }, { "sp", 0 }, { "xr0", 0 }, { "xr1", 1 }, { "xr10", 10 }, { "xr11", 11 }, { "xr12", 12 }, { "xr13", 13 }, { "xr14", 14 }, { "xr15", 15 }, { "xr2", 2 }, { "xr3", 3 }, { "xr4", 4 }, { "xr5", 5 }, { "xr6", 6 }, { "xr7", 7 }, { "xr8", 8 }, { "xr9", 9 },};#define XR_REG_NAME_CNT \ (sizeof (xr_registers) / sizeof (struct reg_name))static const struct reg_name other_registers[] ={ { "mdr", 0 }, { "psw", 0 }, { "sp", 0 },};#define OTHER_REG_NAME_CNT \ (sizeof (other_registers) / sizeof (struct reg_name))/* reg_name_search does a binary search of the given register table to see if "name" is a valid regiter name. Returns the register number from the array on success, or -1 on failure. */static intreg_name_search (regs, regcount, name) const struct reg_name *regs; int regcount; const char *name;{ int middle, low, high; int cmp; low = 0; high = regcount - 1; do { middle = (low + high) / 2; cmp = strcasecmp (name, regs[middle].name); if (cmp < 0) high = middle - 1; else if (cmp > 0) low = middle + 1; else return regs[middle].value; } while (low <= high); return -1;}/* Summary of register_name(). * * in: Input_line_pointer points to 1st char of operand. * * out: A expressionS. * The operand may have been a register: in this case, X_op == O_register, * X_add_number is set to the register number, and truth is returned. * Input_line_pointer->(next non-blank) char after operand, or is in * its original state. */static booleanr_register_name (expressionP) expressionS *expressionP;{ int reg_number; char *name; char *start; char c; /* Find the spelling of the operand. */ start = name = input_line_pointer; c = get_symbol_end (); reg_number = reg_name_search (r_registers, R_REG_NAME_CNT, name); /* Look to see if it's in the register table. */ if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; /* Put back the delimiting char. */ *input_line_pointer = c; return true; } else { /* Reset the line as if we had not done anything. */ /* Put back the delimiting char. */ *input_line_pointer = c; /* Reset input_line pointer. */ input_line_pointer = start; return false; }}/* Summary of register_name(). * * in: Input_line_pointer points to 1st char of operand. * * out: A expressionS. * The operand may have been a register: in this case, X_op == O_register, * X_add_number is set to the register number, and truth is returned. * Input_line_pointer->(next non-blank) char after operand, or is in * its original state. */static booleanxr_register_name (expressionP) expressionS *expressionP;{ int reg_number; char *name; char *start; char c; /* Find the spelling of the operand. */ start = name = input_line_pointer; c = get_symbol_end (); reg_number = reg_name_search (xr_registers, XR_REG_NAME_CNT, name); /* Look to see if it's in the register table. */ if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; /* Put back the delimiting char. */ *input_line_pointer = c; return true; } else { /* Reset the line as if we had not done anything. */ /* Put back the delimiting char. */ *input_line_pointer = c; /* Reset input_line pointer. */ input_line_pointer = start; return false; }}/* Summary of register_name(). * * in: Input_line_pointer points to 1st char of operand. * * out: A expressionS. * The operand may have been a register: in this case, X_op == O_register, * X_add_number is set to the register number, and truth is returned. * Input_line_pointer->(next non-blank) char after operand, or is in * its original state. */static booleandata_register_name (expressionP) expressionS *expressionP;{ int reg_number; char *name; char *start; char c; /* Find the spelling of the operand. */ start = name = input_line_pointer; c = get_symbol_end (); reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name); /* Look to see if it's in the register table. */ if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; /* Put back the delimiting char. */ *input_line_pointer = c; return true; } else { /* Reset the line as if we had not done anything. */ /* Put back the delimiting char. */ *input_line_pointer = c; /* Reset input_line pointer. */ input_line_pointer = start; return false; }}/* Summary of register_name(). * * in: Input_line_pointer points to 1st char of operand. * * out: A expressionS. * The operand may have been a register: in this case, X_op == O_register, * X_add_number is set to the register number, and truth is returned. * Input_line_pointer->(next non-blank) char after operand, or is in * its original state. */static booleanaddress_register_name (expressionP) expressionS *expressionP;{ int reg_number; char *name; char *start; char c; /* Find the spelling of the operand. */ start = name = input_line_pointer; c = get_symbol_end (); reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name); /* Look to see if it's in the register table. */ if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; /* Put back the delimiting char. */ *input_line_pointer = c; return true; } else { /* Reset the line as if we had not done anything. */ /* Put back the delimiting char. */ *input_line_pointer = c; /* Reset input_line pointer. */ input_line_pointer = start; return false; }}/* Summary of register_name(). * * in: Input_line_pointer points to 1st char of operand. * * out: A expressionS. * The operand may have been a register: in this case, X_op == O_register, * X_add_number is set to the register number, and truth is returned. * Input_line_pointer->(next non-blank) char after operand, or is in * its original state. */static booleanother_register_name (expressionP) expressionS *expressionP;{ int reg_number; char *name; char *start; char c; /* Find the spelling of the operand. */ start = name = input_line_pointer; c = get_symbol_end (); reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name); /* Look to see if it's in the register table. */ if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; /* Put back the delimiting char. */ *input_line_pointer = c; return true; } else { /* Reset the line as if we had not done anything. */ /* Put back the delimiting char. */ *input_line_pointer = c; /* Reset input_line pointer. */ input_line_pointer = start; return false; }}voidmd_show_usage (stream) FILE *stream;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -