📄 tc-mn10200.c
字号:
/* tc-mn10200.c -- Assembler code for the Matsushita 10200 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/mn10200.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 */ {0x81, -0x7e, 2, 1}, {0x8004, -0x7ffb, 5, 2}, {0x800006, -0x7ffff9, 7, 0}, /* bCCx relaxing */ {0x81, -0x7e, 3, 4}, {0x8004, -0x7ffb, 6, 5}, {0x800006, -0x7ffff9, 8, 0}, /* jsr relaxing */ {0x8004, -0x7ffb, 3, 7}, {0x800006, -0x7ffff9, 5, 0}, /* jmp relaxing */ {0x81, -0x7e, 2, 9}, {0x8004, -0x7ffb, 3, 10}, {0x800006, -0x7ffff9, 5, 0},};/* Local functions. */static void mn10200_insert_operand PARAMS ((unsigned long *, unsigned long *, const struct mn10200_operand *, offsetT, char *, unsigned, unsigned));static unsigned long check_operand PARAMS ((unsigned long, const struct mn10200_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));/* Fixups. */#define MAX_INSN_FIXUPS (5)struct mn10200_fixup{ expressionS exp; int opindex; bfd_reloc_code_real_type reloc;};struct mn10200_fixup fixups[MAX_INSN_FIXUPS];static int fc;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[] ={ { NULL, NULL, 0 }};/* Opcode hash table. */static struct hash_control *mn10200_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 other_registers[] ={ { "mdr", 0 }, { "psw", 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 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;{ fprintf (stream, _("MN10200 options:\n\none yet\n"));}intmd_parse_option (c, arg) int c; char *arg;{ return 0;}symbolS *md_undefined_symbol (name) char *name;{ return 0;}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 = prec - 1; i >= 0; i--) { md_number_to_chars (litp, (valueT) words[i], 2); litp += 2; } return NULL;}voidmd_convert_frag (abfd, sec, fragP) bfd *abfd; asection *sec; fragS *fragP;{ static unsigned long label_count = 0; char buf[40]; subseg_change (sec, 0); if (fragP->fr_subtype == 0) { fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol, fragP->fr_offset, 1, BFD_RELOC_8_PCREL); fragP->fr_var = 0; fragP->fr_fix += 2; } else if (fragP->fr_subtype == 1) { /* Reverse the condition of the first branch. */ int offset = fragP->fr_fix; int opcode = fragP->fr_literal[offset] & 0xff; switch (opcode) { case 0xe8: opcode = 0xe9; break; case 0xe9: opcode = 0xe8; break; case 0xe0: opcode = 0xe2; break; case 0xe2: opcode = 0xe0; break; case 0xe3: opcode = 0xe1; break; case 0xe1: opcode = 0xe3; break; case 0xe4: opcode = 0xe6; break; case 0xe6: opcode = 0xe4; break; case 0xe7: opcode = 0xe5; break; case 0xe5: opcode = 0xe7; break; default: abort (); } fragP->fr_literal[offset] = opcode; /* Create a fixup for the reversed conditional branch. */ sprintf (buf, ".%s_%d", FAKE_LABEL_NAME, label_count++); fix_new (fragP, fragP->fr_fix + 1, 1, symbol_new (buf, sec, 0, fragP->fr_next), fragP->fr_offset, 1, BFD_RELOC_8_PCREL); /* Now create the unconditional branch + fixup to the final target. */ fragP->fr_literal[offset + 2] = 0xfc; fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol, fragP->fr_offset, 1, BFD_RELOC_16_PCREL); fragP->fr_var = 0; fragP->fr_fix += 5; } else if (fragP->fr_subtype == 2) { /* Reverse the condition of the first branch. */ int offset = fragP->fr_fix; int opcode = fragP->fr_literal[offset] & 0xff; switch (opcode) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -