📄 vax.c
字号:
/* vax.c - vax-specific - Copyright (C) 1987 Free Software Foundation, Inc.This file is part of GAS, the GNU Assembler.GAS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GAS; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *//* JF I moved almost all the vax specific stuff into this one file 'cuz RMS seems to think its a good idea. I hope I managed to get all the VAX-isms */#include "as.h"#include "read.h"#include "flonum.h"#include "vax-inst.h"#include "md.h"#include "obstack.h" /* For FRAG_APPEND_1_CHAR macro in "frags.h" */#include "frags.h"#include "struc-symbol.h"#include "expr.h"#include "symbols.h"/* This is the number to put at the beginning of the a.out file */long omagic = OMAGIC;/* 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[] = "#";/* 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. */static expressionS /* Hold details of an operand expression */ exp_of_operand[VIT_MAX_OPERANDS];static struct vit v; /* A vax instruction after decoding. */LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER]; /* Hold details of big operands. */FLONUM_TYPE float_operand[VIT_MAX_OPERANDS]; /* Above is made to point into */ /* big_operand_bits by md_begin(). *//* * 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, long2a. 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 bbssi e6 bbcci e7 Always, you complement 0th bit to reverse condition. Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement2c. 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 instructionto 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 outafter 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))const relax_typeSmd_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 */};#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))voidmd_begin (){ char *vip_begin (); char *errtxt; FLONUM_TYPE *fP; int i; if (*(errtxt = vip_begin (TRUE, "$", "*", "`"))) { 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_end (){ vip_end ();}void /* Knows about order of bytes in address. */md_number_to_chars (con, value, nbytes) char con[]; /* Return 'nbytes' of chars here. */ long int value; /* The value of the bits. */ int nbytes; /* Number of bytes in the output. */{ int n; long v; n = nbytes; v = value; while (nbytes--) { *con++ = value; /* Lint wants & MASK_CHAR. */ value >>= BITS_PER_CHAR; } /* XXX line number probably botched for this warning message. */ if (value != 0 && value != -1) as_warn ("Displacement (%ld) long for instruction field length (%d).", v, n);}void /* Knows about order of bytes in address. */md_number_to_imm (con, value, nbytes) char con[]; /* Return 'nbytes' of chars here. */ long int value; /* The value of the bits. */ int nbytes; /* Number of bytes in the output. */{ int n; long v; n = nbytes; v = value; while (nbytes--) { *con++ = value; /* Lint wants & MASK_CHAR. */ value >>= BITS_PER_CHAR; } /* XXX line number probably botched for this warning message. */ if (value != 0 && value != -1) as_warn ("Displacement (%ld) too long for instruction field length (%d).", v, n);}void /* Knows about order of bytes in address. */md_number_to_disp (con, value, nbytes) char con[]; /* Return 'nbytes' of chars here. */ long int value; /* The value of the bits. */ int nbytes; /* Number of bytes in the output. */{ abort (); while (nbytes--) { *con++ = value; /* Lint wants & MASK_CHAR. */ value >>= BITS_PER_CHAR; } /* XXX line number probably botched for this warning message. */ if (value != 0 && value != -1) as_warn ("Displacement too long for instruction field length.");}void /* Knows about order of bytes in address. */md_number_to_field (con, value, nbytes) char con[]; /* Return 'nbytes' of chars here. */ long int value; /* The value of the bits. */ int nbytes; /* Number of bytes in the output. */{ abort (); while (nbytes--) { *con++ = value; /* Lint wants & MASK_CHAR. */ value >>= BITS_PER_CHAR; } /* XXX line number probably botched for this warning message. */ if (value != 0 && value != -1) as_warn ("Displacement too long for instruction field length.");}long int /* Knows about the byte order in a word. */md_chars_to_number (con, nbytes) unsigned char con[]; /* Low order byte 1st. */ int nbytes; /* Number of bytes in the input. */{ long int 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. */{ char *p; register struct vop *operandP;/* An operand. Scans all operands. */ char *save_input_line_pointer; char c_save; /* What used to live after an expression. */ struct frag *fragP; /* Fragment of code we just made. */ register int goofed; /* TRUE: instruction_string bad for all passes. */ register struct vop *end_operandP; /* -> slot just after last operand */ /* Limit of the for (each operand). */ register expressionS *expP; /* -> expression values for this operand */ /* These refer to an instruction operand expression. */ segT to_seg; /* Target segment of the address. */ register valueT this_add_number; register struct symbol *this_add_symbol; /* +ve (minuend) symbol. */ register struct symbol *this_subtract_symbol; /* -ve(subtrahend) symbol. */ long int opcode_as_number; /* As a number. */ char *opcode_as_chars; /* Least significant byte 1st. */ /* As an array of characters. */ char *opcode_low_byteP; /* Least significant byte 1st */ struct details *detP; /* The details of an ADxxx frag. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -