sparc-dis.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 983 行 · 第 1/2 页
C
983 行
/* Print SPARC instructions. Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.This program 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 2 of the License, or(at your option) any later version.This program 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 this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <stdio.h>#include "sysdep.h"#include "opcode/sparc.h"#include "dis-asm.h"#include "libiberty.h"#include "opintl.h"/* Bitmask of v9 architectures. */#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \ | (1 << SPARC_OPCODE_ARCH_V9A) \ | (1 << SPARC_OPCODE_ARCH_V9B))/* 1 if INSN is for v9 only. */#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))/* 1 if INSN is for v9. */#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)/* The sorted opcode table. */static const struct sparc_opcode **sorted_opcodes;/* For faster lookup, after insns are sorted they are hashed. *//* ??? I think there is room for even more improvement. */#define HASH_SIZE 256/* It is important that we only look at insn code bits as that is how the opcode table is hashed. OPCODE_BITS is a table of valid bits for each of the main types (0,1,2,3). */static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };#define HASH_INSN(INSN) \ ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))struct opcode_hash { struct opcode_hash *next; const struct sparc_opcode *opcode;};static struct opcode_hash *opcode_hash_table[HASH_SIZE];static void build_hash_table PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int));static int is_delayed_branch PARAMS ((unsigned long));static int compare_opcodes PARAMS ((const PTR, const PTR));static int compute_arch_mask PARAMS ((unsigned long));/* Sign-extend a value which is N bits long. */#define SEX(value, bits) \ ((((int)(value)) << ((8 * sizeof (int)) - bits)) \ >> ((8 * sizeof (int)) - bits) )static char *reg_names[] ={ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",/* psr, wim, tbr, fpsr, cpsr are v8 only. */ "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"};#define freg_names (®_names[4 * 8])/* These are ordered according to there register number in rdpr and wrpr insns. */static char *v9_priv_reg_names[] ={ "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl", "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", "wstate", "fq" /* "ver" - special cased */};/* These are ordered according to there register number in rd and wr insns (-16). */static char *v9a_asr_reg_names[] ={ "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint", "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr"};/* Macros used to extract instruction fields. Not all fields have macros defined here, only those which are actually used. */#define X_RD(i) (((i) >> 25) & 0x1f)#define X_RS1(i) (((i) >> 14) & 0x1f)#define X_LDST_I(i) (((i) >> 13) & 1)#define X_ASI(i) (((i) >> 5) & 0xff)#define X_RS2(i) (((i) >> 0) & 0x1f)#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1))#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n))#define X_DISP22(i) (((i) >> 0) & 0x3fffff)#define X_IMM22(i) X_DISP22 (i)#define X_DISP30(i) (((i) >> 0) & 0x3fffffff)/* These are for v9. */#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))#define X_DISP19(i) (((i) >> 0) & 0x7ffff)#define X_MEMBAR(i) ((i) & 0x7f)/* Here is the union which was used to extract instruction fields before the shift and mask macros were written. union sparc_insn { unsigned long int code; struct { unsigned int anop:2; #define op ldst.anop unsigned int anrd:5; #define rd ldst.anrd unsigned int op3:6; unsigned int anrs1:5; #define rs1 ldst.anrs1 unsigned int i:1; unsigned int anasi:8; #define asi ldst.anasi unsigned int anrs2:5; #define rs2 ldst.anrs2 #define shcnt rs2 } ldst; struct { unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; unsigned int IMM13:13; #define imm13 IMM13.IMM13 } IMM13; struct { unsigned int anop:2; unsigned int a:1; unsigned int cond:4; unsigned int op2:3; unsigned int DISP22:22; #define disp22 branch.DISP22 #define imm22 disp22 } branch; struct { unsigned int anop:2; unsigned int a:1; unsigned int z:1; unsigned int rcond:3; unsigned int op2:3; unsigned int DISP16HI:2; unsigned int p:1; unsigned int _rs1:5; unsigned int DISP16LO:14; } branch16; struct { unsigned int anop:2; unsigned int adisp30:30; #define disp30 call.adisp30 } call; }; *//* Nonzero if INSN is the opcode for a delayed branch. */static intis_delayed_branch (insn) unsigned long insn;{ struct opcode_hash *op; for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) { CONST struct sparc_opcode *opcode = op->opcode; if ((opcode->match & insn) == opcode->match && (opcode->lose & insn) == 0) return (opcode->flags & F_DELAYED); } return 0;}/* extern void qsort (); *//* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value to compare_opcodes. */static unsigned int current_arch_mask;/* Print one instruction from MEMADDR on INFO->STREAM. We suffix the instruction with a comment that gives the absolute address involved, as well as its symbolic form, if the instruction is preceded by a findable `sethi' and it either adds an immediate displacement to that register, or it is an `add' or `or' instruction on that register. */intprint_insn_sparc (memaddr, info) bfd_vma memaddr; disassemble_info *info;{ FILE *stream = info->stream; bfd_byte buffer[4]; unsigned long insn; register struct opcode_hash *op; /* Nonzero of opcode table has been initialized. */ static int opcodes_initialized = 0; /* bfd mach number of last call. */ static unsigned long current_mach = 0; bfd_vma (*getword) PARAMS ((const unsigned char *)); if (!opcodes_initialized || info->mach != current_mach) { int i; current_arch_mask = compute_arch_mask (info->mach); if (!opcodes_initialized) sorted_opcodes = (const struct sparc_opcode **) xmalloc (sparc_num_opcodes * sizeof (struct sparc_opcode *)); /* Reset the sorted table so we can resort it. */ for (i = 0; i < sparc_num_opcodes; ++i) sorted_opcodes[i] = &sparc_opcodes[i]; qsort ((char *) sorted_opcodes, sparc_num_opcodes, sizeof (sorted_opcodes[0]), compare_opcodes); build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); current_mach = info->mach; opcodes_initialized = 1; } { int status = (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); if (status != 0) { (*info->memory_error_func) (status, memaddr, info); return -1; } } /* On SPARClite variants such as DANlite (sparc86x), instructions are always big-endian even when the machine is in little-endian mode. */ if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite) getword = bfd_getb32; else getword = bfd_getl32; insn = getword (buffer); info->insn_info_valid = 1; /* We do return this info */ info->insn_type = dis_nonbranch; /* Assume non branch insn */ info->branch_delay_insns = 0; /* Assume no delay */ info->target = 0; /* Assume no target known */ for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) { CONST struct sparc_opcode *opcode = op->opcode; /* If the insn isn't supported by the current architecture, skip it. */ if (! (opcode->architecture & current_arch_mask)) continue; if ((opcode->match & insn) == opcode->match && (opcode->lose & insn) == 0) { /* Nonzero means that we have found an instruction which has the effect of adding or or'ing the imm13 field to rs1. */ int imm_added_to_rs1 = 0; int imm_ored_to_rs1 = 0; /* Nonzero means that we have found a plus sign in the args field of the opcode table. */ int found_plus = 0; /* Nonzero means we have an annulled branch. */ int is_annulled = 0; /* Do we have an `add' or `or' instruction combining an immediate with rs1? */ if (opcode->match == 0x80102000) /* or */ imm_ored_to_rs1 = 1; if (opcode->match == 0x80002000) /* add */ imm_added_to_rs1 = 1; if (X_RS1 (insn) != X_RD (insn) && strchr (opcode->args, 'r') != 0) /* Can't do simple format if source and dest are different. */ continue; if (X_RS2 (insn) != X_RD (insn) && strchr (opcode->args, 'O') != 0) /* Can't do simple format if source and dest are different. */ continue; (*info->fprintf_func) (stream, opcode->name); { register CONST char *s; if (opcode->args[0] != ',') (*info->fprintf_func) (stream, " "); for (s = opcode->args; *s != '\0'; ++s) { while (*s == ',') { (*info->fprintf_func) (stream, ","); ++s; switch (*s) { case 'a': (*info->fprintf_func) (stream, "a"); is_annulled = 1; ++s; continue; case 'N': (*info->fprintf_func) (stream, "pn"); ++s; continue; case 'T': (*info->fprintf_func) (stream, "pt"); ++s; continue; default: break; } /* switch on arg */ } /* while there are comma started args */ (*info->fprintf_func) (stream, " "); switch (*s) { case '+': found_plus = 1; /* note fall-through */ default: (*info->fprintf_func) (stream, "%c", *s); break; case '#': (*info->fprintf_func) (stream, "0"); break;#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) case '1': case 'r': reg (X_RS1 (insn)); break; case '2': case 'O': reg (X_RS2 (insn)); break; case 'd': reg (X_RD (insn)); break;#undef reg#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n])#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)]) case 'e': freg (X_RS1 (insn)); break; case 'v': /* double/even */ case 'V': /* quad/multiple of 4 */ fregx (X_RS1 (insn)); break; case 'f': freg (X_RS2 (insn)); break; case 'B': /* double/even */ case 'R': /* quad/multiple of 4 */ fregx (X_RS2 (insn)); break; case 'g': freg (X_RD (insn)); break; case 'H': /* double/even */ case 'J': /* quad/multiple of 4 */ fregx (X_RD (insn)); break;#undef freg#undef fregx#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) case 'b': creg (X_RS1 (insn)); break; case 'c': creg (X_RS2 (insn)); break; case 'D': creg (X_RD (insn)); break;#undef creg case 'h': (*info->fprintf_func) (stream, "%%hi(%#x)", (0xFFFFFFFF & ((int) X_IMM22 (insn) << 10))); break; case 'i': /* 13 bit immediate */ case 'I': /* 11 bit immediate */ case 'j': /* 10 bit immediate */ { int imm; if (*s == 'i') imm = X_SIMM (insn, 13); else if (*s == 'I') imm = X_SIMM (insn, 11); else imm = X_SIMM (insn, 10); /* Check to see whether we have a 1+i, and take note of that fact. Note: because of the way we sort the table, we will be matching 1+i rather than i+1, so it is OK to assume that i is after +, not before it. */ if (found_plus) imm_added_to_rs1 = 1; if (imm <= 9) (*info->fprintf_func) (stream, "%d", imm); else (*info->fprintf_func) (stream, "%#x", imm); } break; case 'X': /* 5 bit unsigned immediate */ case 'Y': /* 6 bit unsigned immediate */ { int imm = X_IMM (insn, *s == 'X' ? 5 : 6); if (imm <= 9) (info->fprintf_func) (stream, "%d", imm); else (info->fprintf_func) (stream, "%#x", (unsigned) imm); } break; case '3': (info->fprintf_func) (stream, "%d", X_IMM (insn, 3)); break; case 'K': { int mask = X_MEMBAR (insn); int bit = 0x40, printed_one = 0; const char *name; if (mask == 0) (info->fprintf_func) (stream, "0"); else while (bit) { if (mask & bit) { if (printed_one) (info->fprintf_func) (stream, "|"); name = sparc_decode_membar (bit); (info->fprintf_func) (stream, "%s", name); printed_one = 1; } bit >>= 1; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?