📄 tc-tahoe.c
字号:
/* This file is tc-tahoe.c Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1995, 2000 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 "obstack.h"/* This bit glommed from tahoe-inst.h. */typedef unsigned char byte;typedef byte tahoe_opcodeT;/* This is part of tahoe-ins-parse.c & friends. We want to parse a tahoe instruction text into a tree defined here. */#define TIT_MAX_OPERANDS (4) /* maximum number of operands in one single tahoe instruction */struct top /* tahoe instruction operand */ { int top_ndx; /* -1, or index register. eg 7=[R7] */ int top_reg; /* -1, or register number. eg 7 = R7 or (R7) */ byte top_mode; /* Addressing mode byte. This byte, defines which of the 11 modes opcode is. */ char top_access; /* Access type wanted for this opperand 'b'branch ' 'no-instruction 'amrvw' */ char top_width; /* Operand width expected, one of "bwlq?-:!" */ char * top_error; /* Say if operand is inappropriate */ segT seg_of_operand; /* segment as returned by expression()*/ expressionS exp_of_operand; /* The expression as parsed by expression()*/ byte top_dispsize; /* Number of bytes in the displacement if we can figure it out */ };/* The addressing modes for an operand. These numbers are the acutal values for certain modes, so be carefull if you screw with them. */#define TAHOE_DIRECT_REG (0x50)#define TAHOE_REG_DEFERRED (0x60)#define TAHOE_REG_DISP (0xE0)#define TAHOE_REG_DISP_DEFERRED (0xF0)#define TAHOE_IMMEDIATE (0x8F)#define TAHOE_IMMEDIATE_BYTE (0x88)#define TAHOE_IMMEDIATE_WORD (0x89)#define TAHOE_IMMEDIATE_LONGWORD (0x8F)#define TAHOE_ABSOLUTE_ADDR (0x9F)#define TAHOE_DISPLACED_RELATIVE (0xEF)#define TAHOE_DISP_REL_DEFERRED (0xFF)#define TAHOE_AUTO_DEC (0x7E)#define TAHOE_AUTO_INC (0x8E)#define TAHOE_AUTO_INC_DEFERRED (0x9E)/* INDEXED_REG is decided by the existance or lack of a [reg]. *//* These are encoded into top_width when top_access=='b' and it's a psuedo op. */#define TAHOE_WIDTH_ALWAYS_JUMP '-'#define TAHOE_WIDTH_CONDITIONAL_JUMP '?'#define TAHOE_WIDTH_BIG_REV_JUMP '!'#define TAHOE_WIDTH_BIG_NON_REV_JUMP ':'/* The hex code for certain tahoe commands and modes. This is just for readability. */#define TAHOE_JMP (0x71)#define TAHOE_PC_REL_LONG (0xEF)#define TAHOE_BRB (0x11)#define TAHOE_BRW (0x13)/* These, when 'ored' with, or added to, a register number, set up the number for the displacement mode. */#define TAHOE_PC_OR_BYTE (0xA0)#define TAHOE_PC_OR_WORD (0xC0)#define TAHOE_PC_OR_LONG (0xE0)struct tit /* Get it out of the sewer, it stands for tahoe instruction tree (Geeze!). */{ tahoe_opcodeT tit_opcode; /* The opcode. */ byte tit_operands; /* How many operands are here. */ struct top tit_operand[TIT_MAX_OPERANDS]; /* Operands */ char *tit_error; /* "" or fatal error text */};/* end: tahoe-inst.h *//* tahoe.c - tahoe-specific - Not part of gas yet. */#include "opcode/tahoe.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 or a quoted string. */const char comment_chars[] = "#;";/* These chars only start a comment at the beginning of a line. */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 0d1.234E-12 (see exp chars above) Note: The Tahoe port doesn't support floating point constants. This is consistant with 'as' If it's needed, I can always add it later. */const char FLT_CHARS[] = "df";/* 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. (The tahoe has plenty of room, so the change currently isn't needed.) */static struct tit t; /* A tahoe instruction after decoding. */void float_cons ();/* A table of pseudo ops (sans .), the function called, and an integer op that the function is called with. */const pseudo_typeS md_pseudo_table[] ={ {"dfloat", float_cons, 'd'}, {"ffloat", float_cons, 'f'}, {0}};/* * For Tahoe, relative addresses of "just the right length" are pretty easy. * The branch displacement is always the last operand, even in * synthetic instructions. * For Tahoe, 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 four states are listed below. * The "how long" refers merely to the displacement length. * The address usually has some constant bytes in it as well. *States for Tahoe address relaxing.1. TAHOE_WIDTH_ALWAYS_JUMP (-) Format: "b-" Tahoe opcodes are: (Hex) jr 11 jbr 11 Simple branch. Always, 1 byte opcode, then displacement/absolute. If word or longword, change opcode to brw or jmp.2. TAHOE_WIDTH_CONDITIONAL_JUMP (?) J<cond> where <cond> is a simple flag test. Format: "b?" Tahoe opcodes are: (Hex) jneq/jnequ 21 jeql/jeqlu 31 jgtr 41 jleq 51 jgeq 81 jlss 91 jgtru a1 jlequ b1 jvc c1 jvs d1 jlssu/jcs e1 jgequ/jcc f1 Always, you complement 4th bit to reverse the condition. Always, 1-byte opcode, then 1-byte displacement.3. TAHOE_WIDTH_BIG_REV_JUMP (!) Jbc/Jbs where cond tests a memory bit. Format: "rlvlb!" Tahoe opcodes are: (Hex) jbs 0e jbc 1e Always, you complement 4th bit to reverse the condition. Always, 1-byte opcde, longword, longword-address, 1-word-displacement4. TAHOE_WIDTH_BIG_NON_REV_JUMP (:) JaoblXX/Jbssi Format: "rlmlb:" Tahoe opcodes are: (Hex) aojlss 2f jaoblss 2f aojleq 3f jaobleq 3f jbssi 5f Always, we cannot reverse the sense of the branch; we have a word displacement.We need to modify the opcode is for class 1, 2 and 3 instructions.After relax() we may complement the 4th bit of 2 or 3 to reverse sense ofbranch.We sometimes store context in the operand literal. This way we can figure outafter relax() what the original addressing mode was. (Was is pc_rel, orpc_rel_disp? That sort of thing.) *//* These displacements are relative to the START address of the displacement which is at the start of the displacement, not the end of the instruction. The hardware pc_rel is at the end of the instructions. That's why all the displacements have the length of the displacement added to them. (WF + length(word)) 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)#define STATE_ALWAYS_BRANCH (1)#define STATE_CONDITIONAL_BRANCH (2)#define STATE_BIG_REV_BRANCH (3)#define STATE_BIG_NON_REV_BRANCH (4)#define STATE_PC_RELATIVE (5)#define STATE_BYTE (0)#define STATE_WORD (1)#define STATE_LONG (2)#define STATE_UNDF (3) /* Symbol undefined in pass1 *//* This is the table used by gas to figure out relaxing modes. The fields are forward_branch reach, backward_branch reach, number of bytes it would take, where the next biggest branch is. */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 *//* Unconditional branch cases "jrb" The relax part is the actual displacement */ { BF, BB, 1, C (1, 1) }, /* brb B`foo 1,0 */ { WF, WB, 2, C (1, 2) }, /* brw W`foo 1,1 */ { 0, 0, 5, 0 }, /* Jmp L`foo 1,2 */ { 1, 1, 0, 0 }, /* unused 1,3 *//* Reversible Conditional Branch. If the branch won't reach, reverse it, and jump over a brw or a jmp that will reach. The relax part is the actual address. */ { BF, BB, 1, C (2, 1) }, /* b<cond> B`foo 2,0 */ { WF + 2, WB + 2, 4, C (2, 2) }, /* brev over, brw W`foo, over: 2,1 */ { 0, 0, 7, 0 }, /* brev over, jmp L`foo, over: 2,2 */ { 1, 1, 0, 0 }, /* unused 2,3 *//* Another type of reversable branch. But this only has a word displacement. */ { 1, 1, 0, 0 }, /* unused 3,0 */ { WF, WB, 2, C (3, 2) }, /* jbX W`foo 3,1 */ { 0, 0, 8, 0 }, /* jrevX over, jmp L`foo, over: 3,2 */ { 1, 1, 0, 0 }, /* unused 3,3 *//* These are the non reversable branches, all of which have a word displacement. If I can't reach, branch over a byte branch, to a jump that will reach. The jumped branch jumps over the reaching branch, to continue with the flow of the program. It's like playing leap frog. */ { 1, 1, 0, 0 }, /* unused 4,0 */ { WF, WB, 2, C (4, 2) }, /* aobl_ W`foo 4,1 */ { 0, 0, 10, 0 }, /*aobl_ W`hop,br over,hop: jmp L^foo,over 4,2*/ { 1, 1, 0, 0 }, /* unused 4,3 *//* Normal displacement mode, no jumping or anything like that. The relax points to one byte before the address, thats why all the numbers are up by one. */ { BF + 1, BB + 1, 2, C (5, 1) }, /* B^"foo" 5,0 */ { WF + 1, WB + 1, 3, C (5, 2) }, /* W^"foo" 5,1 */ { 0, 0, 5, 0 }, /* L^"foo" 5,2 */ { 1, 1, 0, 0 }, /* unused 5,3 */};#undef C#undef BF#undef BB#undef WF#undef WB/* End relax stuff *//* Handle of the OPCODE hash table. NULL means any use before md_begin() will crash. */static struct hash_control *op_hash;/* Init function. Build the hash table. */voidmd_begin (){ struct tot *tP; char *errorval = 0; int synthetic_too = 1; /* If 0, just use real opcodes. */ op_hash = hash_new (); for (tP = totstrs; *tP->name && !errorval; tP++) errorval = hash_insert (op_hash, tP->name, &tP->detail); if (synthetic_too) for (tP = synthetic_totstrs; *tP->name && !errorval; tP++) errorval = hash_insert (op_hash, tP->name, &tP->detail); if (errorval) as_fatal (errorval);}CONST char *md_shortopts = "ad:STt:V";struct option md_longopts[] = { {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);intmd_parse_option (c, arg) int c; char *arg;{ switch (c) { case 'a': as_warn (_("The -a option doesn't exist. (Despite what the man page says!")); break; case 'd': as_warn (_("Displacement length %s ignored!"), arg); break; case 'S': as_warn (_("SYMBOL TABLE not implemented")); break; case 'T': as_warn (_("TOKEN TRACE not implemented")); break; case 't': as_warn (_("I don't need or use temp. file \"%s\"."), arg); break; case 'V': as_warn (_("I don't use an interpass file! -V ignored")); break; default: return 0; } return 1;}voidmd_show_usage (stream) FILE *stream;{ fprintf (stream, _("\Tahoe options:\n\-a ignored\n\-d LENGTH ignored\n\-J ignored\n\-S ignored\n\-t FILE ignored\n\-T ignored\n\-V ignored\n"));}/* The functions in this section take numbers in the machine format, and munges them into Tahoe byte order. They exist primarily for cross assembly purpose. */void /* Knows about order of bytes in address. */md_number_to_chars (con, value, nbytes) char con[]; /* Return 'nbytes' of chars here. */ valueT value; /* The value of the bits. */ int nbytes; /* Number of bytes in the output. */{ number_to_chars_bigendian (con, value, nbytes);}#ifdef commentvoid /* 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. */{ md_number_to_chars (con, value, nbytes);}#endif /* comment */voidtc_apply_fix (fixP, val) fixS *fixP; long val;{ /* should never be called */ know (0);}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. */{ md_number_to_chars (con, value, nbytes);}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. */{ md_number_to_chars (con, value, nbytes);}/* Put the bits in an order that a tahoe will understand, despite the ordering of the native machine. On Tahoe: first 4 bytes are normal unsigned big endian long, next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last). The last byte is broken up with bit 7 as pcrel, bits 6 & 5 as length,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -