📄 tc-vax.c
字号:
/* tc-vax.c - vax-specific - Copyright 1987, 1991, 1992, 1993, 1994, 1995, 1998, 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 "as.h"#include "vax-inst.h"#include "obstack.h" /* For FRAG_APPEND_1_CHAR macro in "frags.h" *//* These chars start a comment anywhere in a source file (except inside another comment */const char comment_chars[] = "#";/* These chars only start a comment at the beginning of a line. *//* Note that for the VAX the are the same as comment_chars above. */const char line_comment_chars[] = "#";const char line_separator_chars[] = ";";/* Chars that can be used to separate mant from exp in floating point nums */const char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant *//* as in 0f123.456 *//* or 0H1.234E-12 (see exp chars above) */const char FLT_CHARS[] = "dDfFgGhH";/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be changed in read.c . Ideally it shouldn't have to know about it at all, but nothing is ideal around here. *//* Hold details of an operand expression */static expressionS exp_of_operand[VIT_MAX_OPERANDS];static segT seg_of_operand[VIT_MAX_OPERANDS];/* A vax instruction after decoding. */static struct vit v;/* Hold details of big operands. */LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER];FLONUM_TYPE float_operand[VIT_MAX_OPERANDS];/* Above is made to point into big_operand_bits by md_begin(). */int flag_hash_long_names; /* -+ */int flag_one; /* -1 */int flag_show_after_trunc; /* -H */int flag_no_hash_mixed_case; /* -h NUM *//* * For VAX, relative addresses of "just the right length" are easy. * The branch displacement is always the last operand, even in * synthetic instructions. * For VAX, we encode the relax_substateTs (in e.g. fr_substate) as: * * 4 3 2 1 0 bit number * ---/ /--+-------+-------+-------+-------+-------+ * | what state ? | how long ? | * ---/ /--+-------+-------+-------+-------+-------+ * * The "how long" bits are 00=byte, 01=word, 10=long. * This is a Un*x convention. * Not all lengths are legit for a given value of (what state). * The "how long" refers merely to the displacement length. * The address usually has some constant bytes in it as well. * groups for VAX address relaxing. 1. "foo" pc-relative. length of byte, word, long 2a. J<cond> where <cond> is a simple flag test. length of byte, word, long. VAX opcodes are: (Hex) bneq/bnequ 12 beql/beqlu 13 bgtr 14 bleq 15 bgeq 18 blss 19 bgtru 1a blequ 1b bvc 1c bvs 1d bgequ/bcc 1e blssu/bcs 1f Always, you complement 0th bit to reverse condition. Always, 1-byte opcode, then 1-byte displacement. 2b. J<cond> where cond tests a memory bit. length of byte, word, long. Vax opcodes are: (Hex) bbs e0 bbc e1 bbss e2 bbcs e3 bbsc e4 bbcc e5 Always, you complement 0th bit to reverse condition. Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement 2c. J<cond> where cond tests low-order memory bit length of byte,word,long. Vax opcodes are: (Hex) blbs e8 blbc e9 Always, you complement 0th bit to reverse condition. Always, 1-byte opcode, longword-address, 1-byte displacement. 3. Jbs/Jbr. length of byte,word,long. Vax opcodes are: (Hex) bsbb 10 brb 11 These are like (2) but there is no condition to reverse. Always, 1 byte opcode, then displacement/absolute. 4a. JacbX length of word, long. Vax opcodes are: (Hex) acbw 3d acbf 4f acbd 6f abcb 9d acbl f1 acbg 4ffd acbh 6ffd Always, we cannot reverse the sense of the branch; we have a word displacement. The double-byte op-codes don't hurt: we never want to modify the opcode, so we don't care how many bytes are between the opcode and the operand. 4b. JXobXXX length of long, long, byte. Vax opcodes are: (Hex) aoblss f2 aobleq f3 sobgeq f4 sobgtr f5 Always, we cannot reverse the sense of the branch; we have a byte displacement. The only time we need to modify the opcode is for class 2 instructions. After relax() we may complement the lowest order bit of such instruction to reverse sense of branch. For class 2 instructions, we store context of "where is the opcode literal". We can change an opcode's lowest order bit without breaking anything else. We sometimes store context in the operand literal. This way we can figure out after relax() what the original addressing mode was. *//* These displacements are relative to the start address of the displacement. The first letter is Byte, Word. 2nd letter is Forward, Backward. */#define BF (1+ 127)#define BB (1+-128)#define WF (2+ 32767)#define WB (2+-32768)/* Dont need LF, LB because they always reach. [They are coded as 0.] */#define C(a,b) ENCODE_RELAX(a,b)/* This macro has no side-effects. */#define ENCODE_RELAX(what,length) (((what) << 2) + (length))#define RELAX_STATE(s) ((s) >> 2)#define RELAX_LENGTH(s) ((s) & 3)const relax_typeS md_relax_table[] ={ {1, 1, 0, 0}, /* error sentinel 0,0 */ {1, 1, 0, 0}, /* unused 0,1 */ {1, 1, 0, 0}, /* unused 0,2 */ {1, 1, 0, 0}, /* unused 0,3 */ {BF + 1, BB + 1, 2, C (1, 1)},/* B^"foo" 1,0 */ {WF + 1, WB + 1, 3, C (1, 2)},/* W^"foo" 1,1 */ {0, 0, 5, 0}, /* L^"foo" 1,2 */ {1, 1, 0, 0}, /* unused 1,3 */ {BF, BB, 1, C (2, 1)}, /* b<cond> B^"foo" 2,0 */ {WF + 2, WB + 2, 4, C (2, 2)},/* br.+? brw X 2,1 */ {0, 0, 7, 0}, /* br.+? jmp X 2,2 */ {1, 1, 0, 0}, /* unused 2,3 */ {BF, BB, 1, C (3, 1)}, /* brb B^foo 3,0 */ {WF, WB, 2, C (3, 2)}, /* brw W^foo 3,1 */ {0, 0, 5, 0}, /* Jmp L^foo 3,2 */ {1, 1, 0, 0}, /* unused 3,3 */ {1, 1, 0, 0}, /* unused 4,0 */ {WF, WB, 2, C (4, 2)}, /* acb_ ^Wfoo 4,1 */ {0, 0, 10, 0}, /* acb_,br,jmp L^foo4,2 */ {1, 1, 0, 0}, /* unused 4,3 */ {BF, BB, 1, C (5, 1)}, /* Xob___,,foo 5,0 */ {WF + 4, WB + 4, 6, C (5, 2)},/* Xob.+2,brb.+3,brw5,1 */ {0, 0, 9, 0}, /* Xob.+2,brb.+6,jmp5,2 */ {1, 1, 0, 0}, /* unused 5,3 */};#undef C#undef BF#undef BB#undef WF#undef WBvoid float_cons ();const pseudo_typeS md_pseudo_table[] ={ {"dfloat", float_cons, 'd'}, {"ffloat", float_cons, 'f'}, {"gfloat", float_cons, 'g'}, {"hfloat", float_cons, 'h'}, {0},};#define STATE_PC_RELATIVE (1)#define STATE_CONDITIONAL_BRANCH (2)#define STATE_ALWAYS_BRANCH (3) /* includes BSB... */#define STATE_COMPLEX_BRANCH (4)#define STATE_COMPLEX_HOP (5)#define STATE_BYTE (0)#define STATE_WORD (1)#define STATE_LONG (2)#define STATE_UNDF (3) /* Symbol undefined in pass1 */#define min(a, b) ((a) < (b) ? (a) : (b))int flonum_gen2vax PARAMS ((char format_letter, FLONUM_TYPE * f, LITTLENUM_TYPE * words));static const char *vip_begin PARAMS ((int, const char *, const char *, const char *));static void vip_op_defaults PARAMS ((const char *, const char *, const char *));static void vip_op PARAMS ((char *, struct vop *));static void vip PARAMS ((struct vit *, char *));voidmd_begin (){ const char *errtxt; FLONUM_TYPE *fP; int i; if ((errtxt = vip_begin (1, "$", "*", "`")) != 0) { as_fatal (_("VIP_BEGIN error:%s"), errtxt); } for (i = 0, fP = float_operand; fP < float_operand + VIT_MAX_OPERANDS; i++, fP++) { fP->low = &big_operand_bits[i][0]; fP->high = &big_operand_bits[i][SIZE_OF_LARGE_NUMBER - 1]; }}voidmd_number_to_chars (con, value, nbytes) char con[]; valueT value; int nbytes;{ number_to_chars_littleendian (con, value, nbytes);}/* Fix up some data or instructions after we find out the value of a symbol that they reference. */void /* Knows about order of bytes in address. */md_apply_fix (fixP, value) fixS *fixP; long value;{ number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal, (valueT) value, fixP->fx_size);}longmd_chars_to_number (con, nbytes) unsigned char con[]; /* Low order byte 1st. */ int nbytes; /* Number of bytes in the input. */{ long retval; for (retval = 0, con += nbytes - 1; nbytes--; con--) { retval <<= BITS_PER_CHAR; retval |= *con; } return retval;}/* vax:md_assemble() emit frags for 1 instruction */voidmd_assemble (instruction_string) char *instruction_string; /* A string: assemble 1 instruction. */{ /* Non-zero if operand expression's segment is not known yet. */ int is_undefined; int length_code; char *p; /* An operand. Scans all operands. */ struct vop *operandP; char *save_input_line_pointer; /* What used to live after an expression. */ char c_save; /* 1: instruction_string bad for all passes. */ int goofed; /* Points to slot just after last operand. */ struct vop *end_operandP; /* Points to expression values for this operand. */ expressionS *expP; segT *segP; /* These refer to an instruction operand expression. */ /* Target segment of the address. */ segT to_seg; valueT this_add_number; /* Positive (minuend) symbol. */ symbolS *this_add_symbol; /* As a number. */ long opcode_as_number; /* Least significant byte 1st. */ char *opcode_as_chars; /* As an array of characters. */ /* Least significant byte 1st */ char *opcode_low_byteP; /* length (bytes) meant by vop_short. */ int length; /* 0, or 1 if '@' is in addressing mode. */ int at; /* From vop_nbytes: vax_operand_width (in bytes) */ int nbytes; FLONUM_TYPE *floatP; LITTLENUM_TYPE literal_float[8]; /* Big enough for any floating point literal. */ vip (&v, instruction_string); /* * Now we try to find as many as_warn()s as we can. If we do any as_warn()s * then goofed=1. Notice that we don't make any frags yet. * Should goofed be 1, then this instruction will wedge in any pass, * and we can safely flush it, without causing interpass symbol phase * errors. That is, without changing label values in different passes. */ if ((goofed = (*v.vit_error)) != 0) { as_warn (_("Ignoring statement due to \"%s\""), v.vit_error); } /* * We need to use expression() and friends, which require us to diddle * input_line_pointer. So we save it and restore it later. */ save_input_line_pointer = input_line_pointer; for (operandP = v.vit_operand, expP = exp_of_operand, segP = seg_of_operand, floatP = float_operand, end_operandP = v.vit_operand + v.vit_operands; operandP < end_operandP; operandP++, expP++, segP++, floatP++) { /* for each operand */ if (operandP->vop_error) { as_warn (_("Ignoring statement because \"%s\""), operandP->vop_error); goofed = 1; } else { /* Statement has no syntax goofs: let's sniff the expression. */ int can_be_short = 0; /* 1 if a bignum can be reduced to a short literal. */ input_line_pointer = operandP->vop_expr_begin; c_save = operandP->vop_expr_end[1]; operandP->vop_expr_end[1] = '\0'; /* If to_seg == SEG_PASS1, expression() will have set need_pass_2 = 1. */ *segP = expression (expP); switch (expP->X_op) { case O_absent: /* for BSD4.2 compatibility, missing expression is absolute 0 */ expP->X_op = O_constant; expP->X_add_number = 0; /* For SEG_ABSOLUTE, we shouldn't need to set X_op_symbol, X_add_symbol to any particular value. But, we will program defensively. Since this situation occurs rarely so it costs us little to do, and stops Dean worrying about the origin of random bits in expressionS's. */ expP->X_add_symbol = NULL; expP->X_op_symbol = NULL; break; case O_symbol: case O_constant: break; default: /* * Major bug. We can't handle the case of a * SEG_OP expression in a VIT_OPCODE_SYNTHETIC * variable-length instruction. * We don't have a frag type that is smart enough to * relax a SEG_OP, and so we just force all * SEG_OPs to behave like SEG_PASS1s. * Clearly, if there is a demand we can invent a new or
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -